1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2012 The Android Open Source Project
3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License.
6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at
7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software
11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and
14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License.
15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
1675897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart
172b10554b6c736f3421102d483b74b70bb82f997cChris Masone#include "shill/device.h"
182b10554b6c736f3421102d483b74b70bb82f997cChris Masone
1908add488849f90600a5657a6f54f4dbc34701b8fMatthew Wein#include <errno.h>
205c4dd0b0886fb10deae0d3b40628fb2c521aff99mukesh agrawal#include <netinet/in.h>
21a41ab517725d036b63420f8445550246f8f50b99Alex Vakulenko#include <linux/if.h>  // NOLINT - Needs definitions from netinet/in.h
2275897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart#include <stdio.h>
23b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu#include <string.h>
24208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart#include <sys/param.h>
255c4dd0b0886fb10deae0d3b40628fb2c521aff99mukesh agrawal#include <time.h>
2608add488849f90600a5657a6f54f4dbc34701b8fMatthew Wein#include <unistd.h>
27ee929b7ab2a89bbf2d1aecf85bbd49e53fbea059Chris Masone
28787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan#include <algorithm>
29c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly#include <set>
3075897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart#include <string>
318fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone#include <vector>
3275897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart
333e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/bind.h>
3411c213f3cf64f27a0e42ee6da95e98bd1d4b3202Ben Chan#include <base/files/file_util.h>
35487b8bfc46a91e29bb23aaf3c59cfe67033bfc8bChris Masone#include <base/memory/ref_counted.h>
3638fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart#include <base/stl_util.h>
37a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/stringprintf.h>
3862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu#include <base/strings/string_number_conversions.h>
3962abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu#include <base/strings/string_util.h>
40289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#if defined(__ANDROID__)
41289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#include <dbus/service_constants.h>
42289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#else
433bd3c8c33917221d1074f1aa19272e45c0ce2793Chris Masone#include <chromeos/dbus/service_constants.h>
44289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#endif  // __ANDROID__
45ee929b7ab2a89bbf2d1aecf85bbd49e53fbea059Chris Masone
46f84a4242b4218dc375449ab2d68085226f43ce5bArman Uguray#include "shill/async_connection.h"
47e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart#include "shill/connection.h"
48f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein#include "shill/connection_tester.h"
4975897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart#include "shill/control_interface.h"
50675d0b0f04936050a357722f52dc078a3ab671d8Peter Qiu#include "shill/dhcp/dhcp_config.h"
51675d0b0f04936050a357722f52dc078a3ab671d8Peter Qiu#include "shill/dhcp/dhcp_provider.h"
5215d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein#include "shill/dhcp_properties.h"
538fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone#include "shill/error.h"
5426b327e559583d5a84b7e1605c29a4dcbc87d2a9Paul Stewart#include "shill/event_dispatcher.h"
556d2c72dddf3dbbc6a614d4fa1a7a3d670756c01fGaurav Shah#include "shill/geolocation_info.h"
56f65320cc1c04ea9e09cc8656e87fe9912c601e9aPaul Stewart#include "shill/http_proxy.h"
5762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu#include "shill/icmp.h"
58fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan#include "shill/ip_address_store.h"
59036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart#include "shill/link_monitor.h"
60b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h"
618fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone#include "shill/manager.h"
6285e050b4923878a57aec1415314d2b39ff233e00Thieu Le#include "shill/metrics.h"
638d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/ip_address.h"
648d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/ndisc.h"
658d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_handler.h"
6695207da4b896bd0a4186163f6f9ebda044a5a7b9Chris Masone#include "shill/property_accessor.h"
672b10554b6c736f3421102d483b74b70bb82f997cChris Masone#include "shill/refptr_types.h"
682b10554b6c736f3421102d483b74b70bb82f997cChris Masone#include "shill/service.h"
69f84a4242b4218dc375449ab2d68085226f43ce5bArman Uguray#include "shill/socket_info_reader.h"
705dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone#include "shill/store_interface.h"
71435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah#include "shill/technology.h"
72fa11e28ddb81dab93971d5433a5274a1dc5c8283Paul Stewart#include "shill/tethering.h"
73dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu#include "shill/traffic_monitor.h"
7475897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart
753e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Bind;
766f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiuusing base::Callback;
770e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulkusing base::FilePath;
785dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masoneusing base::StringPrintf;
79c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kellyusing std::set;
808fe2c7eea92541b5282929361a19ad519e0608a9Chris Masoneusing std::string;
818fe2c7eea92541b5282929361a19ad519e0608a9Chris Masoneusing std::vector;
828fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone
8375897df1154ac38b7a4512a687241ad6a197ee40Paul Stewartnamespace shill {
845dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone
85c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinnamespace Logging {
86c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinstatic auto kModuleLogScope = ScopeLogger::kDevice;
87a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartstatic string ObjectID(Device* d) { return d->GetRpcIdentifier(); }
88c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
89c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein
905dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone// static
912bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartconst char Device::kIPFlagTemplate[] = "/proc/sys/net/%s/conf/%s/%s";
922bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart// static
932bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartconst char Device::kIPFlagVersion4[] = "ipv4";
942bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart// static
952bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartconst char Device::kIPFlagVersion6[] = "ipv6";
962bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart// static
972bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartconst char Device::kIPFlagDisableIPv6[] = "disable_ipv6";
982bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart// static
992bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartconst char Device::kIPFlagUseTempAddr[] = "use_tempaddr";
1002bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart// static
1012bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartconst char Device::kIPFlagUseTempAddrUsedAndDefault[] = "2";
102c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart// static
103c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewartconst char Device::kIPFlagReversePathFilter[] = "rp_filter";
104c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart// static
105c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewartconst char Device::kIPFlagReversePathFilterEnabled[] = "1";
106c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart// static
107c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewartconst char Device::kIPFlagReversePathFilterLooseMode[] = "2";
1082bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart// static
1092cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartconst char Device::kIPFlagArpAnnounce[] = "arp_announce";
1102cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart// static
1112cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartconst char Device::kIPFlagArpAnnounceDefault[] = "0";
1122cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart// static
1132cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartconst char Device::kIPFlagArpAnnounceBestLocal[] = "2";
1142cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart// static
1152cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartconst char Device::kIPFlagArpIgnore[] = "arp_ignore";
1162cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart// static
1172cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartconst char Device::kIPFlagArpIgnoreDefault[] = "0";
1182cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart// static
1192cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartconst char Device::kIPFlagArpIgnoreLocalOnly[] = "1";
1202cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart// static
121ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhuconst char Device::kStoragePowered[] = "Powered";
122ba99b598d3f399a41e57f49dccac5f988e653126Prathmesh Prabhu// static
1236ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewartconst char Device::kStorageReceiveByteCount[] = "ReceiveByteCount";
1246ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart// static
1256ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewartconst char Device::kStorageTransmitByteCount[] = "TransmitByteCount";
126b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu// static
127b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiuconst char Device::kFallbackDnsTestHostname[] = "www.gstatic.com";
128b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu// static
129b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiuconst char* Device::kFallbackDnsServers[] = {
130b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu    "8.8.8.8",
131a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu    "8.8.4.4"
132b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu};
133b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu
134b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu// static
135b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiuconst int Device::kDNSTimeoutMilliseconds = 5000;
136a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiuconst int Device::kLinkUnreliableThresholdSeconds = 60 * 60;
13762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiuconst size_t Device::kHardwareAddressLength = 6U;
1385dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone
139a794cd60a7339d576ea2eed263a4f0a20fb255afPaul StewartDevice::Device(ControlInterface* control_interface,
140a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart               EventDispatcher* dispatcher,
141a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart               Metrics* metrics,
142a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart               Manager* manager,
143a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart               const string& link_name,
144a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart               const string& address,
145435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah               int interface_index,
146435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah               Technology::Identifier technology)
1479a24553461df7036755060423f90804011612249Eric Shienbrood    : enabled_(false),
1489a24553461df7036755060423f90804011612249Eric Shienbrood      enabled_persistent_(true),
1499a24553461df7036755060423f90804011612249Eric Shienbrood      enabled_pending_(enabled_),
150b925cc8f481d21fddd9569fc68861f6e5b6e3eaeChris Masone      reconnect_(true),
151626719f89881a949d8b5a8fa808beb924496489fChris Masone      hardware_address_(address),
152f60e406392490f72982e7d1b1acb8b231a620cb7mukesh agrawal      interface_index_(interface_index),
153f60e406392490f72982e7d1b1acb8b231a620cb7mukesh agrawal      running_(false),
154afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov      link_name_(link_name),
15519e30406a1d3123892007d20438527dc4b2f92c3Chris Masone      unique_id_(link_name),
156d9661956a297e6d7a3e5809f50e332dc9c9811a9Darin Petkov      control_interface_(control_interface),
157d9661956a297e6d7a3e5809f50e332dc9c9811a9Darin Petkov      dispatcher_(dispatcher),
1583426c8fc7a3943f2d8fcb2ec78f0593088b42bedThieu Le      metrics_(metrics),
1597df0c672458bee8f4ff33004103351d59a9f4b50Chris Masone      manager_(manager),
1609a24553461df7036755060423f90804011612249Eric Shienbrood      weak_ptr_factory_(this),
16177cb681ab58c6623464a355e646138ab84d38573Darin Petkov      adaptor_(control_interface->CreateDeviceAdaptor(this)),
1629a24553461df7036755060423f90804011612249Eric Shienbrood      portal_detector_callback_(Bind(&Device::PortalDetectorCallback,
1639a24553461df7036755060423f90804011612249Eric Shienbrood                                     weak_ptr_factory_.GetWeakPtr())),
164435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah      technology_(technology),
16585e050b4923878a57aec1415314d2b39ff233e00Thieu Le      portal_attempts_to_online_(0),
1666ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      receive_byte_offset_(0),
1676ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      transmit_byte_offset_(0),
1685c4dd0b0886fb10deae0d3b40628fb2c521aff99mukesh agrawal      dhcp_provider_(DHCPProvider::GetInstance()),
169a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu      rtnl_handler_(RTNLHandler::GetInstance()),
170a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu      time_(Time::GetInstance()),
171f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein      last_link_monitor_failed_time_(0),
172f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein      connection_tester_callback_(Bind(&Device::ConnectionTesterCallback,
1732cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart                                       weak_ptr_factory_.GetWeakPtr())),
1742cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart      is_loose_routing_(false),
175490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan      is_multi_homed_(false),
176490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan      connection_diagnostics_callback_(
177490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan          Bind(&Device::ConnectionDiagnosticsCallback,
178490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan               weak_ptr_factory_.GetWeakPtr())) {
179923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  store_.RegisterConstString(kAddressProperty, &hardware_address_);
180923a5025a5e1138b052cbeffa60ea387d479696fBen Chan
181923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kBgscanMethodProperty: Registered in WiFi
182923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kBgscanShortIntervalProperty: Registered in WiFi
183923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kBgscanSignalThresholdProperty: Registered in WiFi
184923a5025a5e1138b052cbeffa60ea387d479696fBen Chan
185923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kCellularAllowRoamingProperty: Registered in Cellular
186923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kCarrierProperty: Registered in Cellular
187923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kEsnProperty: Registered in Cellular
188923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kHomeProviderProperty: Registered in Cellular
189923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kImeiProperty: Registered in Cellular
190923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kIccidProperty: Registered in Cellular
191923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kImsiProperty: Registered in Cellular
192923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kManufacturerProperty: Registered in Cellular
193923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kMdnProperty: Registered in Cellular
194923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kMeidProperty: Registered in Cellular
195923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kMinProperty: Registered in Cellular
196923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kModelIDProperty: Registered in Cellular
197923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kFirmwareRevisionProperty: Registered in Cellular
198923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kHardwareRevisionProperty: Registered in Cellular
199923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kPRLVersionProperty: Registered in Cellular
200923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kSIMLockStatusProperty: Registered in Cellular
201923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kFoundNetworksProperty: Registered in Cellular
202923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kDBusObjectProperty: Register in Cellular
203923a5025a5e1138b052cbeffa60ea387d479696fBen Chan
204923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  store_.RegisterConstString(kInterfaceProperty, &link_name_);
205674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley  HelpRegisterConstDerivedRpcIdentifier(
206674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley      kSelectedServiceProperty, &Device::GetSelectedServiceRpcIdentifier);
207923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  HelpRegisterConstDerivedRpcIdentifiers(kIPConfigsProperty,
20808afdffc182c7f04a8acdbb63240585069af8040Jason Glasgow                                         &Device::AvailableIPConfigs);
209923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  store_.RegisterConstString(kNameProperty, &link_name_);
210923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  store_.RegisterConstBool(kPoweredProperty, &enabled_);
211923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  HelpRegisterConstDerivedString(kTypeProperty,
212bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawal                                 &Device::GetTechnologyString);
21339a7beb18a0c24c9b73c3cc49008ccdca19f9ac2Ben Chan  HelpRegisterConstDerivedUint64(kLinkMonitorResponseTimeProperty,
214036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart                                 &Device::GetLinkMonitorResponseTime);
215b5790058b625a16e87a0ef1f9a0631f33f00701cJason Glasgow
216b925cc8f481d21fddd9569fc68861f6e5b6e3eaeChris Masone  // TODO(cmasone): Chrome doesn't use this...does anyone?
217923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // store_.RegisterConstBool(kReconnectProperty, &reconnect_);
218b925cc8f481d21fddd9569fc68861f6e5b6e3eaeChris Masone
2194e85161f12699d8eb2116ae24766676ed8227a71Chris Masone  // TODO(cmasone): Figure out what shill concept maps to flimflam's "Network".
220923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // known_properties_.push_back(kNetworksProperty);
221b925cc8f481d21fddd9569fc68861f6e5b6e3eaeChris Masone
222227c774828f02cb2c60fc3588263f67e1a768eb9Wade Guthrie  // kRoamThresholdProperty: Registered in WiFi
223923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kScanningProperty: Registered in WiFi, Cellular
224923a5025a5e1138b052cbeffa60ea387d479696fBen Chan  // kScanIntervalProperty: Registered in WiFi, Cellular
22596e35cf43e6d5aa2378cdae6fea507e5335d12bbSamuel Tan  // kWakeOnWiFiFeaturesEnabledProperty: Registered in WiFi
2266ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
2276ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  if (manager_ && manager_->device_info()) {  // Unit tests may not have these.
2286ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart    manager_->device_info()->GetByteCounts(
2296ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart        interface_index_, &receive_byte_offset_, &transmit_byte_offset_);
23039a7beb18a0c24c9b73c3cc49008ccdca19f9ac2Ben Chan    HelpRegisterConstDerivedUint64(kReceiveByteCountProperty,
231b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan                                   &Device::GetReceiveByteCountProperty);
23239a7beb18a0c24c9b73c3cc49008ccdca19f9ac2Ben Chan    HelpRegisterConstDerivedUint64(kTransmitByteCountProperty,
233b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan                                   &Device::GetTransmitByteCountProperty);
2346ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  }
2356ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
236a0a0efe79e5cf4c13a99f6212e9c98839d7a8ed1Darin Petkov  LOG(INFO) << "Device created: " << link_name_
237a0a0efe79e5cf4c13a99f6212e9c98839d7a8ed1Darin Petkov            << " index " << interface_index_;
23875897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart}
23975897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart
24075897df1154ac38b7a4512a687241ad6a197ee40Paul StewartDevice::~Device() {
241a0a0efe79e5cf4c13a99f6212e9c98839d7a8ed1Darin Petkov  LOG(INFO) << "Device destructed: " << link_name_
242a0a0efe79e5cf4c13a99f6212e9c98839d7a8ed1Darin Petkov            << " index " << interface_index_;
24375897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart}
24475897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart
2458ce932a8ebf3af11f17b814c4e544a305607afcaChristopher Grantvoid Device::Initialize() {
2468ce932a8ebf3af11f17b814c4e544a305607afcaChristopher Grant  SLOG(this, 2) << "Initialized";
2478ce932a8ebf3af11f17b814c4e544a305607afcaChristopher Grant  DisableArpFiltering();
2488ce932a8ebf3af11f17b814c4e544a305607afcaChristopher Grant  EnableReversePathFilter();
2498ce932a8ebf3af11f17b814c4e544a305607afcaChristopher Grant}
2508ce932a8ebf3af11f17b814c4e544a305607afcaChristopher Grant
251f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewartvoid Device::LinkEvent(unsigned flags, unsigned change) {
252c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << link_name_
253c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << std::showbase << std::hex
254c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " flags " << flags << " changed " << change
255c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << std::dec << std::noshowbase;
256f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewart}
257f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewart
258a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::Scan(ScanType scan_type, Error* error, const string& reason) {
259c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " [Device] on " << link_name() << " from "
260c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << reason;
26134f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
262be005174bce39ddad185c2eb6808117484d522adPaul Stewart                        "Device doesn't support scan.");
263f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewart}
264f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewart
265a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::SetSchedScan(bool enable, Error* error) {
266d51b24406ed78691abe1c8110029a197c351a6e9Peter Qiu  SLOG(this, 2) << __func__ << " [Device] on " << link_name();
267d51b24406ed78691abe1c8110029a197c351a6e9Peter Qiu  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
268d51b24406ed78691abe1c8110029a197c351a6e9Peter Qiu                        "Device doesn't support scheduled scan.");
269d51b24406ed78691abe1c8110029a197c351a6e9Peter Qiu}
270d51b24406ed78691abe1c8110029a197c351a6e9Peter Qiu
271a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::RegisterOnNetwork(const std::string& /*network_id*/, Error* error,
272a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                 const ResultCallback& /*callback*/) {
27334f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
274be005174bce39ddad185c2eb6808117484d522adPaul Stewart                        "Device doesn't support network registration.");
2759ae310f08aadf2d865dc131a629670d5d4dee478Darin Petkov}
2769ae310f08aadf2d865dc131a629670d5d4dee478Darin Petkov
277c64fe5e866c5f97a5e5676b28931bc9f6d81946aDarin Petkovvoid Device::RequirePIN(
278a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& /*pin*/, bool /*require*/,
279a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    Error* error, const ResultCallback& /*callback*/) {
280c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
28134f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
2829a24553461df7036755060423f90804011612249Eric Shienbrood                        "Device doesn't support RequirePIN.");
283e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov}
284e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov
285a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::EnterPIN(const string& /*pin*/,
286a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                      Error* error, const ResultCallback& /*callback*/) {
287c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
28834f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
2899a24553461df7036755060423f90804011612249Eric Shienbrood                        "Device doesn't support EnterPIN.");
290e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov}
291e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov
292a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::UnblockPIN(const string& /*unblock_code*/,
293a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                        const string& /*pin*/,
294a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                        Error* error, const ResultCallback& /*callback*/) {
295c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
29634f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
2979a24553461df7036755060423f90804011612249Eric Shienbrood                        "Device doesn't support UnblockPIN.");
298e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov}
299e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov
300a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::ChangePIN(const string& /*old_pin*/,
301a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                       const string& /*new_pin*/,
302a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                       Error* error, const ResultCallback& /*callback*/) {
303c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
30434f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
3059a24553461df7036755060423f90804011612249Eric Shienbrood                        "Device doesn't support ChangePIN.");
306e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov}
307e42e101ca1e3938ee7c7973a0615154d279c688eDarin Petkov
308a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::Reset(Error* error, const ResultCallback& /*callback*/) {
309c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
31034f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
311ad663e146042b80fcaaaa4902e6ddc156140a356Ben Chan                        "Device doesn't support Reset.");
312ad663e146042b80fcaaaa4902e6ddc156140a356Ben Chan}
313ad663e146042b80fcaaaa4902e6ddc156140a356Ben Chan
314a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::SetCarrier(const string& /*carrier*/,
315a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                        Error* error, const ResultCallback& /*callback*/) {
316c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
31734f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart  Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
318c37a9c4ee413984342d53c6151edcb7dc3800d78Darin Petkov                        "Device doesn't support SetCarrier.");
319c37a9c4ee413984342d53c6151edcb7dc3800d78Darin Petkov}
320c37a9c4ee413984342d53c6151edcb7dc3800d78Darin Petkov
321bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chanbool Device::IsIPv6Allowed() const {
322bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan  return true;
323bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan}
324bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan
3252bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartvoid Device::DisableIPv6() {
326c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
3272bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagDisableIPv6, "1");
3282bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart}
3292bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart
3302bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartvoid Device::EnableIPv6() {
331c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
332bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan  if (!IsIPv6Allowed()) {
333bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan    LOG(INFO) << "Skip enabling IPv6 on " << link_name_
334bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan              << " as it is not allowed.";
335bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan    return;
336bcc6e016d71c396feefa1ace75b5dcfcd116c659Ben Chan  }
3372bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagDisableIPv6, "0");
3382bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart}
3392bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart
3402bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartvoid Device::EnableIPv6Privacy() {
3412bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv6, kIPFlagUseTempAddr,
3422bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart            kIPFlagUseTempAddrUsedAndDefault);
3432bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart}
3442bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart
3452cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartvoid Device::SetLooseRouting(bool is_loose_routing) {
3462cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  if (is_loose_routing == is_loose_routing_) {
3472cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    return;
3482cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  }
3492cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  is_loose_routing_ = is_loose_routing;
3502cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  if (is_multi_homed_) {
3512cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    // Nothing to do: loose routing is already enabled, and should remain so.
3522cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    return;
3532cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  }
3542cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  if (is_loose_routing) {
3552cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    DisableReversePathFilter();
3562cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  } else {
3572cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    EnableReversePathFilter();
3582cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  }
3592cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart}
3602cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart
361c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewartvoid Device::DisableReversePathFilter() {
362c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart  // TODO(pstew): Current kernel doesn't offer reverse-path filtering flag
363ee6b3d7f9d49fa52072a352fbb59f06127b1ba4cPaul Stewart  // for IPv6.  crbug.com/207193
364c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagReversePathFilter,
365c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart            kIPFlagReversePathFilterLooseMode);
366c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart}
367c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart
368c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewartvoid Device::EnableReversePathFilter() {
369c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagReversePathFilter,
370c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart            kIPFlagReversePathFilterEnabled);
371c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart}
372c8f4bef3c2a277d052f96ae06e67d3e7ab44a592Paul Stewart
3732cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartvoid Device::SetIsMultiHomed(bool is_multi_homed) {
3742cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  if (is_multi_homed == is_multi_homed_) {
3752cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    return;
3762cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  }
3772cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  LOG(INFO) << "Device " << FriendlyName() << " multi-home state is now "
3782cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart            << is_multi_homed;
3792cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  is_multi_homed_ = is_multi_homed;
3802cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  if (is_multi_homed) {
3812cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    EnableArpFiltering();
3822cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    if (!is_loose_routing_) {
3832cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart      DisableReversePathFilter();
3842cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    }
3852cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  } else {
3862cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    DisableArpFiltering();
3872cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    if (!is_loose_routing_) {
3882cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart      EnableReversePathFilter();
3892cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart    }
3902cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  }
3912cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart}
3922cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart
3932cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartvoid Device::DisableArpFiltering() {
3942cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpAnnounce,
3952cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart            kIPFlagArpAnnounceDefault);
3962cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpIgnore, kIPFlagArpIgnoreDefault);
3972cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart}
3982cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart
3992cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewartvoid Device::EnableArpFiltering() {
4002cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpAnnounce,
4012cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart            kIPFlagArpAnnounceBestLocal);
4022cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart  SetIPFlag(IPAddress::kFamilyIPv4, kIPFlagArpIgnore,
4032cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart            kIPFlagArpIgnoreLocalOnly);
4042cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart}
4052cb3fa7317cfa3248cff72d0b9d64c4f2f630472Paul Stewart
406435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shahbool Device::IsConnected() const {
407435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah  if (selected_service_)
408435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah    return selected_service_->IsConnected();
409435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah  return false;
410435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah}
411435de2cd55a95836381b53acbce8cbbad98ec04dGaurav Shah
412a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::IsConnectedToService(const ServiceRefPtr& service) const {
413d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart  return service == selected_service_ && IsConnected();
414d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart}
415d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart
416fa11e28ddb81dab93971d5433a5274a1dc5c8283Paul Stewartbool Device::IsConnectedViaTether() const {
417b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu  if (!ipconfig_.get())
418b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu    return false;
419b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu
420b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu  ByteArray vendor_encapsulated_options =
421b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu      ipconfig_->properties().vendor_encapsulated_options;
422b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu  size_t android_vendor_encapsulated_options_len =
423b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu      strlen(Tethering::kAndroidVendorEncapsulatedOptions);
424b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu
425b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu  return (vendor_encapsulated_options.size() ==
426b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu          android_vendor_encapsulated_options_len) &&
427b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu      !memcmp(&vendor_encapsulated_options[0],
428b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu              Tethering::kAndroidVendorEncapsulatedOptions,
429b2267c9c1cb77564df9d74b5e81689c7e43b8e10Peter Qiu              vendor_encapsulated_options.size());
430fa11e28ddb81dab93971d5433a5274a1dc5c8283Paul Stewart}
431fa11e28ddb81dab93971d5433a5274a1dc5c8283Paul Stewart
432f6b3209a6789171badd65537f72fefb00ca87b8bmukesh agrawalstring Device::GetRpcIdentifier() const {
43327c4aa55b33d3a3836cf70c8f7094bce1c5ead8cChris Masone  return adaptor_->GetRpcIdentifier();
4348fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone}
4358fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone
436515873d543d43b5e7b24c3a48ad0b588370d2216mukesh agrawalstring Device::GetStorageIdentifier() const {
4375dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  string id = GetRpcIdentifier();
4385dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  ControlInterface::RpcIdToStorageId(&id);
439626719f89881a949d8b5a8fa808beb924496489fChris Masone  size_t needle = id.find('_');
44034af218abe6a99144ffe01332ce36fbad94f2628Chris Masone  DLOG_IF(ERROR, needle == string::npos) << "No _ in storage id?!?!";
441626719f89881a949d8b5a8fa808beb924496489fChris Masone  id.replace(id.begin() + needle + 1, id.end(), hardware_address_);
4425dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  return id;
4435dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone}
4445dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone
4456d2c72dddf3dbbc6a614d4fa1a7a3d670756c01fGaurav Shahvector<GeolocationInfo> Device::GetGeolocationObjects() const {
4466d2c72dddf3dbbc6a614d4fa1a7a3d670756c01fGaurav Shah  return vector<GeolocationInfo>();
447227c774828f02cb2c60fc3588263f67e1a768eb9Wade Guthrie}
4486d2c72dddf3dbbc6a614d4fa1a7a3d670756c01fGaurav Shah
449a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartstring Device::GetTechnologyString(Error* /*error*/) {
450b5790058b625a16e87a0ef1f9a0631f33f00701cJason Glasgow  return Technology::NameFromIdentifier(technology());
451b5790058b625a16e87a0ef1f9a0631f33f00701cJason Glasgow}
452b5790058b625a16e87a0ef1f9a0631f33f00701cJason Glasgow
45319e30406a1d3123892007d20438527dc4b2f92c3Chris Masoneconst string& Device::FriendlyName() const {
4547df0c672458bee8f4ff33004103351d59a9f4b50Chris Masone  return link_name_;
455afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov}
456afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov
45719e30406a1d3123892007d20438527dc4b2f92c3Chris Masoneconst string& Device::UniqueName() const {
45819e30406a1d3123892007d20438527dc4b2f92c3Chris Masone  return unique_id_;
45919e30406a1d3123892007d20438527dc4b2f92c3Chris Masone}
46019e30406a1d3123892007d20438527dc4b2f92c3Chris Masone
461a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::Load(StoreInterface* storage) {
4625dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  const string id = GetStorageIdentifier();
4635dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  if (!storage->ContainsGroup(id)) {
46434b3f128bc9f4aa5a48af98a62460ebcdf6c38b4Paul Stewart    SLOG(this, 2) << "Device is not available in the persistent store: " << id;
4655dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone    return false;
4665dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  }
4679a24553461df7036755060423f90804011612249Eric Shienbrood  enabled_persistent_ = true;
4689a24553461df7036755060423f90804011612249Eric Shienbrood  storage->GetBool(id, kStoragePowered, &enabled_persistent_);
4697fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint64_t rx_byte_count = 0, tx_byte_count = 0;
4706ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
4716ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  manager_->device_info()->GetByteCounts(
4726ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      interface_index_, &rx_byte_count, &tx_byte_count);
4736ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  // If there is a byte-count present in the profile, the return value
4746ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  // of Device::Get*ByteCount() should be the this stored value plus
4756ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  // whatever additional bytes we receive since time-of-load.  We
4766ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  // accomplish this by the subtractions below, which can validly
4776ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  // roll over "negative" in the subtractions below and in Get*ByteCount.
4787fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint64_t profile_byte_count;
4796ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  if (storage->GetUint64(id, kStorageReceiveByteCount, &profile_byte_count)) {
4806ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart    receive_byte_offset_ = rx_byte_count - profile_byte_count;
4816ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  }
4826ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  if (storage->GetUint64(id, kStorageTransmitByteCount, &profile_byte_count)) {
4836ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart    transmit_byte_offset_ = tx_byte_count - profile_byte_count;
4846ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  }
4856ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
4865dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  return true;
4875dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone}
4885dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone
489a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::Save(StoreInterface* storage) {
4905dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  const string id = GetStorageIdentifier();
4919a24553461df7036755060423f90804011612249Eric Shienbrood  storage->SetBool(id, kStoragePowered, enabled_persistent_);
492b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan  storage->SetUint64(id, kStorageReceiveByteCount, GetReceiveByteCount());
493b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan  storage->SetUint64(id, kStorageTransmitByteCount, GetTransmitByteCount());
4945dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone  return true;
4955dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone}
4965dec5f4e469a24f1ad508a210d1d23f228bc09a3Chris Masone
497a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnBeforeSuspend(const ResultCallback& callback) {
498fbe8d2b361a51e89fcf1207050729be86a961f5fSamuel Tan  // Nothing to be done in the general case, so immediately report success.
499fbe8d2b361a51e89fcf1207050729be86a961f5fSamuel Tan  callback.Run(Error(Error::kSuccess));
500784566d196431b97657760cab5d805a020b2712amukesh agrawal}
501784566d196431b97657760cab5d805a020b2712amukesh agrawal
502784566d196431b97657760cab5d805a020b2712amukesh agrawalvoid Device::OnAfterResume() {
503787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  RenewDHCPLease();
504bb2231c2d6e39267a3f9e55e74efd9a1ea8e4c98mukesh agrawal  if (link_monitor_) {
505c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << "Informing Link Monitor of resume.";
506bb2231c2d6e39267a3f9e55e74efd9a1ea8e4c98mukesh agrawal    link_monitor_->OnAfterResume();
507bb2231c2d6e39267a3f9e55e74efd9a1ea8e4c98mukesh agrawal  }
508a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  // Resume from sleep, could be in different location now.
509a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  // Ignore previous link monitor failures.
510a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  if (selected_service_) {
511a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    selected_service_->set_unreliable(false);
512a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    reliable_link_callback_.Cancel();
513a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  }
514a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  last_link_monitor_failed_time_ = 0;
515784566d196431b97657760cab5d805a020b2712amukesh agrawal}
516784566d196431b97657760cab5d805a020b2712amukesh agrawal
517a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnDarkResume(const ResultCallback& callback) {
51868b73d232e8a03ed55401f36ea1a72a2b69cf912Samuel Tan  // Nothing to be done in the general case, so immediately report success.
51968b73d232e8a03ed55401f36ea1a72a2b69cf912Samuel Tan  callback.Run(Error(Error::kSuccess));
52064ad2383c4555a99f4f09fe8f5faa088f99f5b90Prathmesh Prabhu}
52164ad2383c4555a99f4f09fe8f5faa088f99f5b90Prathmesh Prabhu
5222b8e44e4559ef85394e868963d9084b4e4148824Darin Petkovvoid Device::DropConnection() {
523c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
5242b8e44e4559ef85394e868963d9084b4e4148824Darin Petkov  DestroyIPConfig();
525cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan  SelectService(nullptr);
5262b8e44e4559ef85394e868963d9084b4e4148824Darin Petkov}
5272b8e44e4559ef85394e868963d9084b4e4148824Darin Petkov
528afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkovvoid Device::DestroyIPConfig() {
5292bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  DisableIPv6();
530d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  bool ipconfig_changed = false;
531afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov  if (ipconfig_.get()) {
532217c61dfafa2ddc800daa227d032d84daf668382Paul Stewart    ipconfig_->ReleaseIP(IPConfig::kReleaseReasonDisconnect);
533cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan    ipconfig_ = nullptr;
534d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    ipconfig_changed = true;
535afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov  }
53625f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  if (ip6config_.get()) {
53725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    StopIPv6DNSServerTimer();
538cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan    ip6config_ = nullptr;
539d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    ipconfig_changed = true;
540d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  }
541d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  if (dhcpv6_config_.get()) {
542d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    dhcpv6_config_->ReleaseIP(IPConfig::kReleaseReasonDisconnect);
543d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    dhcpv6_config_ = nullptr;
544d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    ipconfig_changed = true;
545d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  }
546d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  // Emit updated IP configs if there are any changes.
547d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  if (ipconfig_changed) {
54825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    UpdateIPConfigsProperty();
54925f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  }
550e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart  DestroyConnection();
551afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov}
552afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov
553d4f26486b237fae831d4b682481de785fc99c66ePaul Stewartvoid Device::OnIPv6AddressChanged() {
554d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  IPAddress address(IPAddress::kFamilyIPv6);
555d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  if (!manager_->device_info()->GetPrimaryIPv6Address(
556d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart          interface_index_, &address)) {
557d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    if (ip6config_) {
558cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan      ip6config_ = nullptr;
559d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart      UpdateIPConfigsProperty();
560d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    }
561d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    return;
562d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  }
563d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart
564d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  IPConfig::Properties properties;
565d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  if (!address.IntoString(&properties.address)) {
566d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    LOG(ERROR) << "Unable to convert IPv6 address into a string!";
567d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    return;
568d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  }
569d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  properties.subnet_prefix = address.prefix();
570d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart
571d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  if (!ip6config_) {
572d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    ip6config_ = new IPConfig(control_interface_, link_name_);
573d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  } else if (properties.address == ip6config_->properties().address &&
574d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart             properties.subnet_prefix ==
575d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart                 ip6config_->properties().subnet_prefix) {
576c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << " primary address for "
577c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << link_name_ << " is unchanged.";
578d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    return;
579d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  }
580d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart
581d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  properties.address_family = IPAddress::kFamilyIPv6;
582d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  properties.method = kTypeIPv6;
58325f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  // It is possible for device to receive DNS server notification before IP
58425f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  // address notification, so preserve the saved DNS server if it exist.
58525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  properties.dns_servers = ip6config_->properties().dns_servers;
586c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  PrependDNSServers(IPAddress::kFamilyIPv6, &properties.dns_servers);
587d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  ip6config_->set_properties(properties);
588d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  UpdateIPConfigsProperty();
589b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  OnIPv6ConfigUpdated();
590d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart}
591d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart
5929855170e6e2de08db343640c82795c9b4020a166Peter Qiuvoid Device::OnIPv6DnsServerAddressesChanged() {
59325f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  vector<IPAddress> server_addresses;
5943a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  uint32_t lifetime = 0;
59525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
59625f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  // Stop any existing timer.
59725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  StopIPv6DNSServerTimer();
59825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
59925f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  if (!manager_->device_info()->GetIPv6DnsServerAddresses(
60025f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu          interface_index_, &server_addresses, &lifetime)  || lifetime == 0) {
60125f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    IPv6DNSServerExpired();
60225f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    return;
60325f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  }
60425f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
60525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  vector<string> addresses_str;
606a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  for (const auto& ip : server_addresses) {
60725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    string address_str;
60825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    if (!ip.IntoString(&address_str)) {
60925f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu      LOG(ERROR) << "Unable to convert IPv6 address into a string!";
61025f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu      IPv6DNSServerExpired();
61125f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu      return;
61225f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    }
61325f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    addresses_str.push_back(address_str);
61425f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  }
61525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
61625f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  if (!ip6config_) {
61725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    ip6config_ = new IPConfig(control_interface_, link_name_);
61825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  }
61925f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
620815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan  if (lifetime != ND_OPT_LIFETIME_INFINITY) {
621815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan    // Setup timer to monitor DNS server lifetime if not infinite lifetime.
622815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan    StartIPv6DNSServerTimer(lifetime);
623815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan    ip6config_->UpdateLeaseExpirationTime(lifetime);
624815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan  } else {
625815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan    ip6config_->ResetLeaseExpirationTime();
626815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan  }
627815a6fb99abf0e4921e43784dd1d6f3fcf6415baSamuel Tan
628c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  PrependDNSServers(IPAddress::kFamilyIPv6, &addresses_str);
629c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly
63025f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  // Done if no change in server addresses.
63125f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  if (ip6config_->properties().dns_servers == addresses_str) {
632c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << " IPv6 DNS server list for "
633c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << link_name_ << " is unchanged.";
63425f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    return;
63525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  }
63625f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
63725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  ip6config_->UpdateDNSServers(addresses_str);
63825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  UpdateIPConfigsProperty();
639b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  OnIPv6ConfigUpdated();
64025f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu}
64125f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
6423a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenkovoid Device::StartIPv6DNSServerTimer(uint32_t lifetime_seconds) {
6433a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  int64_t delay = static_cast<int64_t>(lifetime_seconds) * 1000;
64425f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  ipv6_dns_server_expired_callback_.Reset(
64525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu      base::Bind(&Device::IPv6DNSServerExpired, base::Unretained(this)));
64625f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  dispatcher_->PostDelayedTask(ipv6_dns_server_expired_callback_.callback(),
64725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu                               delay);
64825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu}
64925f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
65025f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiuvoid Device::StopIPv6DNSServerTimer() {
65125f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  ipv6_dns_server_expired_callback_.Cancel();
65225f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu}
65325f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
65425f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiuvoid Device::IPv6DNSServerExpired() {
65525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  if (!ip6config_) {
65625f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    return;
65725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  }
65825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  ip6config_->UpdateDNSServers(vector<string>());
65925f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  UpdateIPConfigsProperty();
66025f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu}
66125f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu
66225f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiuvoid Device::StopAllActivities() {
66325f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  StopTrafficMonitor();
66425f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  StopPortalDetection();
665e8303eb267df8904623f16cba64e87df6e8a1563Paul Stewart  StopConnectivityTest();
666490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  StopConnectionDiagnostics();
66725f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  StopLinkMonitor();
66825f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  StopDNSTest();
66925f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  StopIPv6DNSServerTimer();
6709855170e6e2de08db343640c82795c9b4020a166Peter Qiu}
6719855170e6e2de08db343640c82795c9b4020a166Peter Qiu
672a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::AddWakeOnPacketConnection(const string& ip_endpoint,
673a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                       Error* error) {
6745412de0a46893b44f60fee4058c5b0d744b74b4dSamuel Tan  Error::PopulateAndLog(
67534f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart      FROM_HERE, error, Error::kNotSupported,
676fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan      "AddWakeOnPacketConnection not implemented for " + link_name_ + ".");
677fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan  return;
678fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan}
679fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan
680a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::RemoveWakeOnPacketConnection(const string& ip_endpoint,
681a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                          Error* error) {
6825412de0a46893b44f60fee4058c5b0d744b74b4dSamuel Tan  Error::PopulateAndLog(
68334f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart      FROM_HERE, error, Error::kNotSupported,
684fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan      "RemoveWakeOnPacketConnection not implemented for " + link_name_ + ".");
685fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan  return;
686fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan}
687fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan
688a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::RemoveAllWakeOnPacketConnections(Error* error) {
6895412de0a46893b44f60fee4058c5b0d744b74b4dSamuel Tan  Error::PopulateAndLog(
69034f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart      FROM_HERE, error, Error::kNotSupported,
691fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan      "RemoveAllWakeOnPacketConnections not implemented for " + link_name_ +
692fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan          ".");
693fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan  return;
694fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan}
695fe734676357045eab81ab62fc3ea7ae1a40ed905Samuel Tan
696787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tanvoid Device::RenewDHCPLease() {
697787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  LOG(INFO) << __func__;
698787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan
699787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  if (ipconfig_) {
700787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    SLOG(this, 3) << "Renewing IPv4 Address";
701787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    ipconfig_->RenewIP();
702787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  }
703787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  if (ip6config_) {
704787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    SLOG(this, 3) << "Waiting for new IPv6 configuration";
705787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    // Invalidate the old IPv6 configuration, will receive notifications
706787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    // from kernel for new IPv6 configuration if there is one.
707787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    StopIPv6DNSServerTimer();
708787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    ip6config_ = nullptr;
709787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    UpdateIPConfigsProperty();
710787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  }
711d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  if (dhcpv6_config_) {
712d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    SLOG(this, 3) << "Renewing DHCPv6 lease";
713d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    dhcpv6_config_->RenewIP();
714d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  }
715787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan}
716787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan
717ed8e610bb7b8759bcb62b20fbc4ac30a9f242b04Arman Uguraybool Device::ShouldUseArpGateway() const {
718ed8e610bb7b8759bcb62b20fbc4ac30a9f242b04Arman Uguray  return false;
719ed8e610bb7b8759bcb62b20fbc4ac30a9f242b04Arman Uguray}
720ed8e610bb7b8759bcb62b20fbc4ac30a9f242b04Arman Uguray
721316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewartbool Device::IsUsingStaticIP() const {
722316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart  if (!selected_service_) {
723316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart    return false;
724316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart  }
725316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart  return selected_service_->HasStaticIPAddress();
726316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart}
727316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart
728d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kellybool Device::IsUsingStaticNameServers() const {
729d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly  if (!selected_service_) {
730d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly    return false;
731d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly  }
732d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly  return selected_service_->HasStaticNameServers();
733d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly}
734d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly
7352bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewartbool Device::AcquireIPConfig() {
736d408fdf69489e3199c63796a06f7cfbbb4513515Paul Stewart  return AcquireIPConfigWithLeaseName(string());
737d408fdf69489e3199c63796a06f7cfbbb4513515Paul Stewart}
738d408fdf69489e3199c63796a06f7cfbbb4513515Paul Stewart
739a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::AcquireIPConfigWithLeaseName(const string& lease_name) {
740afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov  DestroyIPConfig();
7412bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  EnableIPv6();
742ed8e610bb7b8759bcb62b20fbc4ac30a9f242b04Arman Uguray  bool arp_gateway = manager_->GetArpGateway() && ShouldUseArpGateway();
74315d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein  DHCPConfigRefPtr dhcp_config;
74415d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein  if (selected_service_) {
74515d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein    dhcp_config =
74615d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein        dhcp_provider_->CreateIPv4Config(
74715d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein            link_name_,
74815d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein            lease_name,
74915d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein            arp_gateway,
75015d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein            *(DhcpProperties::Combine(
75115d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein                manager_->dhcp_properties(),
75215d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein                selected_service_->dhcp_properties())));
75315d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein
75415d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein  } else {
75515d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein    dhcp_config =
75615d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein        dhcp_provider_->CreateIPv4Config(link_name_,
75715d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein                                         lease_name,
75815d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein                                         arp_gateway,
75915d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein                                         manager_->dhcp_properties());
76015d5431798155cc83a3fcb8abe0d1a2d5128f7b6Rebecca Silberstein  }
761782cdcea789d76a7ad7802cf9410b14a2399c0a9Garret Kelly  const int minimum_mtu = manager()->GetMinimumMTU();
762782cdcea789d76a7ad7802cf9410b14a2399c0a9Garret Kelly  if (minimum_mtu != IPConfig::kUndefinedMTU) {
763782cdcea789d76a7ad7802cf9410b14a2399c0a9Garret Kelly    dhcp_config->set_minimum_mtu(minimum_mtu);
764782cdcea789d76a7ad7802cf9410b14a2399c0a9Garret Kelly  }
765782cdcea789d76a7ad7802cf9410b14a2399c0a9Garret Kelly
766782cdcea789d76a7ad7802cf9410b14a2399c0a9Garret Kelly  ipconfig_ = dhcp_config;
7679a24553461df7036755060423f90804011612249Eric Shienbrood  ipconfig_->RegisterUpdateCallback(Bind(&Device::OnIPConfigUpdated,
7689a24553461df7036755060423f90804011612249Eric Shienbrood                                         weak_ptr_factory_.GetWeakPtr()));
769c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  ipconfig_->RegisterFailureCallback(Bind(&Device::OnIPConfigFailed,
770c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart                                          weak_ptr_factory_.GetWeakPtr()));
7718223653e57318b02c40d018b47ea32f062734abdPaul Stewart  ipconfig_->RegisterRefreshCallback(Bind(&Device::OnIPConfigRefreshed,
7728223653e57318b02c40d018b47ea32f062734abdPaul Stewart                                          weak_ptr_factory_.GetWeakPtr()));
7731f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart  ipconfig_->RegisterExpireCallback(Bind(&Device::OnIPConfigExpired,
7741f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart                                         weak_ptr_factory_.GetWeakPtr()));
7751062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart  dispatcher_->PostTask(Bind(&Device::ConfigureStaticIPTask,
7761062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart                             weak_ptr_factory_.GetWeakPtr()));
777d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  if (!ipconfig_->RequestIP()) {
778d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    return false;
779d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  }
780d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu
781d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu#ifndef DISABLE_DHCPV6
782d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  // Only start DHCPv6 configuration instance only if DHCPv6 is enabled
783d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  // for this device.
784d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  if (manager_->IsDHCPv6EnabledForDevice(link_name_)) {
785d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu    return AcquireIPv6ConfigWithLeaseName(lease_name);
786d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  }
787d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu#endif  // DISABLE_DHCPV6
788d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  return true;
789d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu}
790d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu
791d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu#ifndef DISABLE_DHCPV6
792d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiubool Device::AcquireIPv6ConfigWithLeaseName(const string& lease_name) {
793d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  auto dhcpv6_config =
794d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu      dhcp_provider_->CreateIPv6Config(link_name_, lease_name);
795d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  dhcpv6_config_ = dhcpv6_config;
796d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  dhcpv6_config_->RegisterUpdateCallback(
797d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu      Bind(&Device::OnDHCPv6ConfigUpdated, weak_ptr_factory_.GetWeakPtr()));
798d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  dhcpv6_config_->RegisterFailureCallback(
799d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu      Bind(&Device::OnDHCPv6ConfigFailed, weak_ptr_factory_.GetWeakPtr()));
800d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  dhcpv6_config_->RegisterExpireCallback(
801d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu      Bind(&Device::OnDHCPv6ConfigExpired, weak_ptr_factory_.GetWeakPtr()));
802d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  if (!dhcpv6_config_->RequestIP()) {
803d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu    return false;
804d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu  }
805d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  return true;
806afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov}
807d1d3278b365e866a7381de2a640219b51fe0e27aPeter Qiu#endif  // DISABLE_DHCPV6
808afa6fc4d31e884af8710deb14798c69b9c9a898eDarin Petkov
809a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::AssignIPConfig(const IPConfig::Properties& properties) {
810539ab0266ef93a3198f12b8be83a6312d35d6ba0Ben Chan  DestroyIPConfig();
811539ab0266ef93a3198f12b8be83a6312d35d6ba0Ben Chan  EnableIPv6();
812539ab0266ef93a3198f12b8be83a6312d35d6ba0Ben Chan  ipconfig_ = new IPConfig(control_interface_, link_name_);
813539ab0266ef93a3198f12b8be83a6312d35d6ba0Ben Chan  ipconfig_->set_properties(properties);
814539ab0266ef93a3198f12b8be83a6312d35d6ba0Ben Chan  dispatcher_->PostTask(Bind(&Device::OnIPConfigUpdated,
8153c3c36a37a885d0a2e180998587af8390744f757Samuel Tan                             weak_ptr_factory_.GetWeakPtr(), ipconfig_, true));
816539ab0266ef93a3198f12b8be83a6312d35d6ba0Ben Chan}
817539ab0266ef93a3198f12b8be83a6312d35d6ba0Ben Chan
818a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::DestroyIPConfigLease(const string& name) {
8190e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulk  dhcp_provider_->DestroyLease(name);
8200e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulk}
8210e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulk
822bebf1b8bce52b88c2cc2d93200b9405f9c19cf21mukesh agrawalvoid Device::HelpRegisterConstDerivedString(
823a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& name,
824a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    string(Device::*get)(Error* error)) {
825b5790058b625a16e87a0ef1f9a0631f33f00701cJason Glasgow  store_.RegisterDerivedString(
826b5790058b625a16e87a0ef1f9a0631f33f00701cJason Glasgow      name,
827cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan      StringAccessor(new CustomAccessor<Device, string>(this, get, nullptr)));
8284e85161f12699d8eb2116ae24766676ed8227a71Chris Masone}
8294e85161f12699d8eb2116ae24766676ed8227a71Chris Masone
830674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wileyvoid Device::HelpRegisterConstDerivedRpcIdentifier(
831a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& name,
832a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    RpcIdentifier(Device::*get)(Error* error)) {
833674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley  store_.RegisterDerivedRpcIdentifier(
834674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley      name,
835674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley      RpcIdentifierAccessor(
836674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley          new CustomAccessor<Device, RpcIdentifier>(this, get, nullptr)));
837674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley}
838674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley
83908afdffc182c7f04a8acdbb63240585069af8040Jason Glasgowvoid Device::HelpRegisterConstDerivedRpcIdentifiers(
840a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& name,
841a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    RpcIdentifiers(Device::*get)(Error*)) {
84208afdffc182c7f04a8acdbb63240585069af8040Jason Glasgow  store_.RegisterDerivedRpcIdentifiers(
84308afdffc182c7f04a8acdbb63240585069af8040Jason Glasgow      name,
84408afdffc182c7f04a8acdbb63240585069af8040Jason Glasgow      RpcIdentifiersAccessor(
845cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan          new CustomAccessor<Device, RpcIdentifiers>(this, get, nullptr)));
84608afdffc182c7f04a8acdbb63240585069af8040Jason Glasgow}
84708afdffc182c7f04a8acdbb63240585069af8040Jason Glasgow
8486ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewartvoid Device::HelpRegisterConstDerivedUint64(
849a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& name,
850a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    uint64_t(Device::*get)(Error*)) {
8516ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  store_.RegisterDerivedUint64(
8526ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      name,
8536ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      Uint64Accessor(
854cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan          new CustomAccessor<Device, uint64_t>(this, get, nullptr)));
8556ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart}
8566ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
857f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silbersteinvoid Device::ConnectionTesterCallback() {
858f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein  LOG(INFO) << "Device " << FriendlyName() << ": Completed Connectivity Test";
859f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein  return;
860f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein}
861f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein
8621062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewartvoid Device::ConfigureStaticIPTask() {
863c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " selected_service " << selected_service_.get()
864c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " ipconfig " << ipconfig_.get();
8651062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart
8661062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart  if (!selected_service_ || !ipconfig_) {
8671062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart    return;
8681062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart  }
8691062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart
870316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart  if (IsUsingStaticIP()) {
871c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << " " << " configuring static IP parameters.";
8721062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart    // If the parameters contain an IP address, apply them now and bring
8731062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart    // the interface up.  When DHCP information arrives, it will supplement
8741062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart    // the static information.
8753c3c36a37a885d0a2e180998587af8390744f757Samuel Tan    OnIPConfigUpdated(ipconfig_, true);
8761062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart  } else {
8778223653e57318b02c40d018b47ea32f062734abdPaul Stewart    // Either |ipconfig_| has just been created in AcquireIPConfig() or
8788223653e57318b02c40d018b47ea32f062734abdPaul Stewart    // we're being called by OnIPConfigRefreshed().  In either case a
8798223653e57318b02c40d018b47ea32f062734abdPaul Stewart    // DHCP client has been started, and will take care of calling
8808223653e57318b02c40d018b47ea32f062734abdPaul Stewart    // OnIPConfigUpdated() when it completes.
881c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << " " << " no static IP address.";
8821062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart  }
8831062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart}
8841062d9deedace1cf4b3b374c5d40c53047fd6778Paul Stewart
885a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::IPConfigCompleted(const IPConfigRefPtr& ipconfig) {
886b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  return ipconfig && !ipconfig->properties().address.empty() &&
887b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu      !ipconfig->properties().dns_servers.empty();
888b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu}
889b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
890b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiuvoid Device::OnIPv6ConfigUpdated() {
891b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  // Setup connection using IPv6 configuration only if the IPv6 configuration
892b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  // is ready for connection (contained both IP address and DNS servers), and
893b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  // there is no existing IPv4 connection. We always prefer IPv4
894b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  // configuration over IPv6.
895b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  if (IPConfigCompleted(ip6config_) &&
896b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu      (!connection_ || connection_->IsIPv6())) {
897b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    SetupConnection(ip6config_);
898b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  }
899b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu}
900b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
901a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::SetupConnection(const IPConfigRefPtr& ipconfig) {
902b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  CreateConnection();
903b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  connection_->UpdateFromIPConfig(ipconfig);
904b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
905300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu  // Report connection type.
906300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu  Metrics::NetworkConnectionIPType ip_type =
907300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu      connection_->IsIPv6() ? Metrics::kNetworkConnectionIPTypeIPv6
908300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu                            : Metrics::kNetworkConnectionIPTypeIPv4;
909300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu  metrics_->NotifyNetworkConnectionIPType(technology_, ip_type);
910300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu
911300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu  // Report if device have IPv6 connectivity
912300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu  bool ipv6_connectivity = IPConfigCompleted(ip6config_);
913300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu  metrics_->NotifyIPv6ConnectivityStatus(technology_, ipv6_connectivity);
914300769ea57941a26bccfa7fe1e1cc4d9ad96b23ePeter Qiu
915b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  // SetConnection must occur after the UpdateFromIPConfig so the
916b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  // service can use the values derived from the connection.
917b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  if (selected_service_) {
918b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    selected_service_->SetConnection(connection_);
919b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
920b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    // The service state change needs to happen last, so that at the
921b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    // time we report the state change to the manager, the service
922b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    // has its connection.
923b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    SetServiceState(Service::kStateConnected);
924b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    OnConnected();
925b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    portal_attempts_to_online_ = 0;
926b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
927b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    // Subtle: Start portal detection after transitioning the service
928b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    // to the Connected state because this call may immediately transition
929b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    // to the Online state.
930b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    StartPortalDetection();
931b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  }
932b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
933208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  SetHostname(ipconfig->properties().accepted_hostname);
934208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  StartLinkMonitor();
935208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  StartTrafficMonitor();
936208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart}
937208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart
938a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::SetHostname(const std::string& hostname) {
939208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  if (hostname.empty() || !manager()->ShouldAcceptHostnameFrom(link_name_)) {
940208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart    return false;
94108add488849f90600a5657a6f54f4dbc34701b8fMatthew Wein  }
94208add488849f90600a5657a6f54f4dbc34701b8fMatthew Wein
943208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  string fixed_hostname = hostname;
944208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  if (fixed_hostname.length() > MAXHOSTNAMELEN) {
945208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart    auto truncate_length = fixed_hostname.find('.');
946208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart    if (truncate_length == string::npos || truncate_length > MAXHOSTNAMELEN) {
947208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart      truncate_length = MAXHOSTNAMELEN;
948208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart    }
949208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart    fixed_hostname.resize(truncate_length);
950208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  }
95108add488849f90600a5657a6f54f4dbc34701b8fMatthew Wein
952208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  return manager_->device_info()->SetHostname(fixed_hostname);
953b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu}
954b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
955a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::PrependDNSServersIntoIPConfig(const IPConfigRefPtr& ipconfig) {
956a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const auto& properties = ipconfig->properties();
957c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly
958c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  vector<string> servers(properties.dns_servers.begin(),
959c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly                         properties.dns_servers.end());
960c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  PrependDNSServers(properties.address_family, &servers);
961c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  if (servers == properties.dns_servers) {
962c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly    // If the server list is the same after being augmented then there's no need
963c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly    // to update the config's list of servers.
964c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly    return;
965c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  }
966c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly
967c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  ipconfig->UpdateDNSServers(servers);
968c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly}
969c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly
970c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kellyvoid Device::PrependDNSServers(const IPAddress::Family family,
971a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                               vector<string>* servers) {
9721ce231c71932200e4d02c71567f8e93788120781Paul Stewart  vector<string>output_servers =
9731ce231c71932200e4d02c71567f8e93788120781Paul Stewart      manager_->FilterPrependDNSServersByFamily(family);
974c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly
9751ce231c71932200e4d02c71567f8e93788120781Paul Stewart  set<string> unique(output_servers.begin(), output_servers.end());
976a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  for (const auto& server : *servers) {
977c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly    if (unique.find(server) == unique.end()) {
9781ce231c71932200e4d02c71567f8e93788120781Paul Stewart      output_servers.push_back(server);
979c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly      unique.insert(server);
980c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly    }
981c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly  }
9821ce231c71932200e4d02c71567f8e93788120781Paul Stewart  servers->swap(output_servers);
983c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly}
984c5f89d131e5b03f448b73fd02d16cab30e438521Garret Kelly
985490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tanvoid Device::ConnectionDiagnosticsCallback(
986490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan      const std::string& connection_issue,
987490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan      const std::vector<ConnectionDiagnostics::Event>& diagnostic_events) {
988490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  SLOG(this, 2) << "Device " << FriendlyName()
989490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan                << ": Completed Connection diagnostics";
990490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  // TODO(samueltan): add connection diagnostics metrics.
991490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan}
992490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan
993a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnIPConfigUpdated(const IPConfigRefPtr& ipconfig,
9943c3c36a37a885d0a2e180998587af8390744f757Samuel Tan                               bool /*new_lease_acquired*/) {
995c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
996c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  if (selected_service_) {
997c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart    ipconfig->ApplyStaticIPParameters(
998c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart        selected_service_->mutable_static_ip_parameters());
999316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart    if (IsUsingStaticIP()) {
1000c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // If we are using a statically configured IP address instead
1001c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // of a leased IP address, release any acquired lease so it may
1002c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // be used by others.  This allows us to merge other non-leased
1003c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // parameters (like DNS) when they're available from a DHCP server
1004c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // and not overridden by static parameters, but at the same time
1005c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // we avoid taking up a dynamic IP address the DHCP server could
1006c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // assign to someone else who might actually use it.
1007c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      ipconfig->ReleaseIP(IPConfig::kReleaseReasonStaticIP);
1008cc0fded2a80c2c6c7fb46cbd7eee578e7a78c50amukesh agrawal    }
1009c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  }
1010d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly  if (!IsUsingStaticNameServers()) {
1011d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly    PrependDNSServersIntoIPConfig(ipconfig);
1012d01b5cc35185e022b66e08832e12fe7f59b5aa24Garret Kelly  }
1013b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  SetupConnection(ipconfig);
1014d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  UpdateIPConfigsProperty();
1015c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart}
1016cc0fded2a80c2c6c7fb46cbd7eee578e7a78c50amukesh agrawal
1017a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnIPConfigFailed(const IPConfigRefPtr& ipconfig) {
1018c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
1019c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  // TODO(pstew): This logic gets yet more complex when multiple
1020c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  // IPConfig types are run in parallel (e.g. DHCP and DHCP6)
1021c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  if (selected_service_) {
1022316acef85ecfc128bf06cc2d2699f21880aa5a7ePaul Stewart    if (IsUsingStaticIP()) {
1023c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // Consider three cases:
1024c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //
1025c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // 1. We're here because DHCP failed while starting up. There
1026c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    are two subcases:
1027c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    a. DHCP has failed, and Static IP config has _not yet_
1028c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //       completed. It's fine to do nothing, because we'll
1029c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //       apply the static config shortly.
1030c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    b. DHCP has failed, and Static IP config has _already_
1031c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //       completed. It's fine to do nothing, because we can
1032c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //       continue to use the static config that's already
1033c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //       been applied.
1034c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //
1035c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      // 2. We're here because a previously valid DHCP configuration
1036c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    is no longer valid. There's still a static IP config,
1037c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    because the condition in the if clause evaluated to true.
1038c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    Furthermore, the static config includes an IP address for
1039c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    us to use.
1040c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //
1041c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    The current configuration may include some DHCP
1042c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    parameters, overriden by any static parameters
1043c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    provided. We continue to use this configuration, because
1044c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    the only configuration element that is leased to us (IP
1045c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      //    address) will be overriden by a static parameter.
1046c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart      return;
1047c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart    }
1048c39f1134c8f1ca15324a7eb2ba9ccc243bc82531Paul Stewart  }
1049c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart
1050c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  ipconfig->ResetProperties();
1051d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  UpdateIPConfigsProperty();
1052b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
10538f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu  // Fallback to IPv6 if possible.
10548f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu  if (IPConfigCompleted(ip6config_)) {
10558f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu    if (!connection_ || !connection_->IsIPv6()) {
10568f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu      // Setup IPv6 connection.
10578f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu      SetupConnection(ip6config_);
10588f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu    } else {
10598f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu      // Ignore IPv4 config failure, since IPv6 is up.
10608f254a17249abf206ad08c5bb17e4499f08ab5d2Peter Qiu    }
1061b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    return;
1062b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  }
1063b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
1064b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu  OnIPConfigFailure();
1065c5099532b82fe201fe2510c43b529944a0930d2ePaul Stewart  DestroyConnection();
10668fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone}
10678fe2c7eea92541b5282929361a19ad519e0608a9Chris Masone
1068a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnIPConfigRefreshed(const IPConfigRefPtr& ipconfig) {
10698223653e57318b02c40d018b47ea32f062734abdPaul Stewart  // Clear the previously applied static IP parameters.
10708223653e57318b02c40d018b47ea32f062734abdPaul Stewart  ipconfig->RestoreSavedIPParameters(
10718223653e57318b02c40d018b47ea32f062734abdPaul Stewart      selected_service_->mutable_static_ip_parameters());
10728223653e57318b02c40d018b47ea32f062734abdPaul Stewart
10738223653e57318b02c40d018b47ea32f062734abdPaul Stewart  dispatcher_->PostTask(Bind(&Device::ConfigureStaticIPTask,
10748223653e57318b02c40d018b47ea32f062734abdPaul Stewart                             weak_ptr_factory_.GetWeakPtr()));
10758223653e57318b02c40d018b47ea32f062734abdPaul Stewart}
10768223653e57318b02c40d018b47ea32f062734abdPaul Stewart
1077f6f9648d5b2beb387ada690b8a20482c694433f1Paul Stewartvoid Device::OnIPConfigFailure() {
1078f6f9648d5b2beb387ada690b8a20482c694433f1Paul Stewart  if (selected_service_) {
1079f6f9648d5b2beb387ada690b8a20482c694433f1Paul Stewart    Error error;
10800d06119be3224788ba1aa65ed24bc8e46b56b949Samuel Tan    selected_service_->DisconnectWithFailure(Service::kFailureDHCP,
10810d06119be3224788ba1aa65ed24bc8e46b56b949Samuel Tan                                             &error,
10820d06119be3224788ba1aa65ed24bc8e46b56b949Samuel Tan                                             __func__);
1083f6f9648d5b2beb387ada690b8a20482c694433f1Paul Stewart  }
1084f6f9648d5b2beb387ada690b8a20482c694433f1Paul Stewart}
1085f6f9648d5b2beb387ada690b8a20482c694433f1Paul Stewart
1086a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnIPConfigExpired(const IPConfigRefPtr& ipconfig) {
10871f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart  metrics()->SendToUMA(
10881f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart      metrics()->GetFullMetricName(
1089132e96ff1c3dade1b08cdae82b0f4ed27a9a45d0mukesh agrawal          Metrics::kMetricExpiredLeaseLengthSecondsSuffix, technology()),
10901f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart      ipconfig->properties().lease_duration_seconds,
10911f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart      Metrics::kMetricExpiredLeaseLengthSecondsMin,
10921f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart      Metrics::kMetricExpiredLeaseLengthSecondsMax,
10931f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart      Metrics::kMetricExpiredLeaseLengthSecondsNumBuckets);
10941f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart}
10951f916e4adae8f937b9023e74307bde8ef8743282Paul Stewart
1096a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnDHCPv6ConfigUpdated(const IPConfigRefPtr& ipconfig,
1097d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu                                   bool /*new_lease_acquired*/) {
1098d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  // Emit configuration update.
1099d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  UpdateIPConfigsProperty();
1100d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu}
1101d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu
1102a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnDHCPv6ConfigFailed(const IPConfigRefPtr& ipconfig) {
1103d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  // Reset configuration data.
1104d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  ipconfig->ResetProperties();
1105d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  UpdateIPConfigsProperty();
1106d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu}
1107d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu
1108a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnDHCPv6ConfigExpired(const IPConfigRefPtr& ipconfig) {
1109d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  // Reset configuration data.
1110d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  ipconfig->ResetProperties();
1111d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  UpdateIPConfigsProperty();
1112d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu}
1113d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu
1114a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiuvoid Device::OnConnected() {
1115a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  if (selected_service_->unreliable()) {
1116a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    // Post a delayed task to reset link back to reliable if no link
1117a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    // failure is detected in the next 5 minutes.
1118a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    reliable_link_callback_.Reset(
1119a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu        base::Bind(&Device::OnReliableLink, base::Unretained(this)));
1120a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    dispatcher_->PostDelayedTask(
1121a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu        reliable_link_callback_.callback(),
1122a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu        kLinkUnreliableThresholdSeconds * 1000);
1123a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  }
1124a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu}
11255519e9e7021ba05af8c38291710746fac3528f21Christopher Wiley
11268596f9f1341d3698543e1010ac1710cbe91e35d5Paul Stewartvoid Device::OnConnectionUpdated() {
11278596f9f1341d3698543e1010ac1710cbe91e35d5Paul Stewart  if (selected_service_) {
11288596f9f1341d3698543e1010ac1710cbe91e35d5Paul Stewart    manager_->UpdateService(selected_service_);
11298596f9f1341d3698543e1010ac1710cbe91e35d5Paul Stewart  }
11308596f9f1341d3698543e1010ac1710cbe91e35d5Paul Stewart}
11318596f9f1341d3698543e1010ac1710cbe91e35d5Paul Stewart
1132e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewartvoid Device::CreateConnection() {
1133c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
1134e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart  if (!connection_.get()) {
113523ac6b72d44c446bca88175883ba26b39c5ed817mukesh agrawal    connection_ = new Connection(interface_index_,
113623ac6b72d44c446bca88175883ba26b39c5ed817mukesh agrawal                                 link_name_,
113723ac6b72d44c446bca88175883ba26b39c5ed817mukesh agrawal                                 technology_,
1138608ec29525f553d51f0a92e84176e3d4b45930a9Peter Qiu                                 manager_->device_info(),
1139608ec29525f553d51f0a92e84176e3d4b45930a9Peter Qiu                                 control_interface_);
1140e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart  }
1141e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart}
1142e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart
1143e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewartvoid Device::DestroyConnection() {
1144c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << " on " << link_name_;
114525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu  StopAllActivities();
1146be5f5b341ba4b85d45ffb6c0430ef5ab84c7b961Paul Stewart  if (selected_service_.get()) {
1147c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << "Clearing connection of service "
1148c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << selected_service_->unique_name();
1149cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan    selected_service_->SetConnection(nullptr);
1150be5f5b341ba4b85d45ffb6c0430ef5ab84c7b961Paul Stewart  }
1151cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan  connection_ = nullptr;
1152e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart}
1153e613202d36e3bfb06a40eea1888694413210ef7ePaul Stewart
1154a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::SelectService(const ServiceRefPtr& service) {
1155c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << ": service "
1156c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << (service ? service->unique_name() : "*reset*")
1157c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " on " << link_name_;
11588a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal
11598a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal  if (selected_service_.get() == service.get()) {
11608a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal    // No change to |selected_service_|. Return early to avoid
11618a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal    // changing its state.
11628a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal    return;
11638a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal  }
11648a3188dbc04245c17a4729d16a632547ce4bf585mukesh agrawal
1165be5f5b341ba4b85d45ffb6c0430ef5ab84c7b961Paul Stewart  if (selected_service_.get()) {
1166be5f5b341ba4b85d45ffb6c0430ef5ab84c7b961Paul Stewart    if (selected_service_->state() != Service::kStateFailure) {
1167be5f5b341ba4b85d45ffb6c0430ef5ab84c7b961Paul Stewart      selected_service_->SetState(Service::kStateIdle);
1168be5f5b341ba4b85d45ffb6c0430ef5ab84c7b961Paul Stewart    }
116920b0a09afa73250a276863c51b7c80ebee332369Paul Stewart    // Just in case the Device subclass has not already done so, make
117020b0a09afa73250a276863c51b7c80ebee332369Paul Stewart    // sure the previously selected service has its connection removed.
1171cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan    selected_service_->SetConnection(nullptr);
1172a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    // Reset link status for the previously selected service.
1173a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    selected_service_->set_unreliable(false);
1174a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu    reliable_link_callback_.Cancel();
117525f1be6cc1919da0af4564127db3a98ab5555c10Peter Qiu    StopAllActivities();
117603dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart  }
1177a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu
1178a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  // Newly selected service (network), previous failures doesn't apply
1179a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  // anymore.
1180a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  last_link_monitor_failed_time_ = 0;
1181a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu
118203dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart  selected_service_ = service;
1183674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley  adaptor_->EmitRpcIdentifierChanged(
1184674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley      kSelectedServiceProperty, GetSelectedServiceRpcIdentifier(nullptr));
118503dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart}
118603dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart
118703dba0bccc3a39cded5083212e56713a6d349e01Paul Stewartvoid Device::SetServiceState(Service::ConnectState state) {
118803dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart  if (selected_service_.get()) {
118903dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart    selected_service_->SetState(state);
119003dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart  }
119103dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart}
119203dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart
119303dba0bccc3a39cded5083212e56713a6d349e01Paul Stewartvoid Device::SetServiceFailure(Service::ConnectFailure failure_state) {
119403dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart  if (selected_service_.get()) {
119503dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart    selected_service_->SetFailure(failure_state);
119603dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart  }
119703dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart}
119803dba0bccc3a39cded5083212e56713a6d349e01Paul Stewart
1199cc95c5dcc848552c87d1368fbb655a93666b6659Eric Shienbroodvoid Device::SetServiceFailureSilent(Service::ConnectFailure failure_state) {
1200cc95c5dcc848552c87d1368fbb655a93666b6659Eric Shienbrood  if (selected_service_.get()) {
1201cc95c5dcc848552c87d1368fbb655a93666b6659Eric Shienbrood    selected_service_->SetFailureSilent(failure_state);
1202cc95c5dcc848552c87d1368fbb655a93666b6659Eric Shienbrood  }
1203cc95c5dcc848552c87d1368fbb655a93666b6659Eric Shienbrood}
1204cc95c5dcc848552c87d1368fbb655a93666b6659Eric Shienbrood
1205a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::SetIPFlag(IPAddress::Family family, const string& flag,
1206a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                       const string& value) {
12072bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  string ip_version;
12082bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  if (family == IPAddress::kFamilyIPv4) {
12092bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart    ip_version = kIPFlagVersion4;
12102bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  } else if (family == IPAddress::kFamilyIPv6) {
12112bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart    ip_version = kIPFlagVersion6;
12122bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  } else {
12132bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart    NOTIMPLEMENTED();
12142bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  }
12152bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  FilePath flag_file(StringPrintf(kIPFlagTemplate, ip_version.c_str(),
12162bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart                                  link_name_.c_str(), flag.c_str()));
1217c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Writing " << value << " to flag file "
1218c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << flag_file.value();
12196fbf64f493a9aae7d743888039c61a57386203dbBen Chan  if (base::WriteFile(flag_file, value.c_str(), value.length()) != 1) {
122038fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart    string message = StringPrintf("IP flag write failed: %s to %s",
122138fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart                                  value.c_str(), flag_file.value().c_str());
122238fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart    if (!base::PathExists(flag_file) &&
122338fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart        ContainsValue(written_flags_, flag_file.value())) {
122438fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart      SLOG(this, 2) << message << " (device is no longer present?)";
122538fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart    } else {
122638fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart      LOG(ERROR) << message;
122738fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart    }
12282bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart    return false;
122938fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart  } else {
123038fcf16b182fae0e3dd88403ac5362c9f16f1297Paul Stewart    written_flags_.insert(flag_file.value());
12312bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  }
12322bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart  return true;
12332bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart}
12342bf1d356e76564adb64b8bc8bc1049e74bf8e4d8Paul Stewart
1235a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartstring Device::PerformTDLSOperation(const string& /* operation */,
1236a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                    const string& /* peer */,
1237a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                    Error* /* error */) {
1238c6fbad96f565fda1caae9cd80569314685c99b90Paul Stewart  return "";
1239c6fbad96f565fda1caae9cd80569314685c99b90Paul Stewart}
1240c6fbad96f565fda1caae9cd80569314685c99b90Paul Stewart
12416ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewartvoid Device::ResetByteCounters() {
12426ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  manager_->device_info()->GetByteCounts(
12436ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      interface_index_, &receive_byte_offset_, &transmit_byte_offset_);
12446ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  manager_->UpdateDevice(this);
12456ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart}
12466ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
1247d215af6f72d012f43057c34f17a12506baa21e66Paul Stewartbool Device::RestartPortalDetection() {
1248d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart  StopPortalDetection();
1249d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart  return StartPortalDetection();
1250d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart}
1251d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart
1252c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewartbool Device::RequestPortalDetection() {
1253c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  if (!selected_service_) {
1254c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << FriendlyName()
1255c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": No selected service, so no need for portal check.";
1256c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    return false;
1257c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  }
1258c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
1259c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  if (!connection_.get()) {
1260c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << FriendlyName()
1261c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": No connection, so no need for portal check.";
1262c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    return false;
1263c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  }
1264c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
1265c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  if (selected_service_->state() != Service::kStatePortal) {
1266c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << FriendlyName()
1267c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Service is not in portal state.  "
1268c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << "No need to start check.";
1269c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    return false;
1270c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  }
1271c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
1272c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  if (!connection_->is_default()) {
1273c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << FriendlyName()
1274c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Service is not the default connection.  "
1275c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << "Don't start check.";
1276c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    return false;
1277c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  }
1278c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
1279c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  if (portal_detector_.get() && portal_detector_->IsInProgress()) {
1280c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << FriendlyName()
1281c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Portal detection is already running.";
1282c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    return true;
1283c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  }
1284c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
1285c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  return StartPortalDetection();
1286c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart}
1287c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
128820088d860631a67c151a12783fbbee63c708792fPaul Stewartbool Device::StartPortalDetection() {
1289457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov  DCHECK(selected_service_);
1290d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart  if (selected_service_->IsPortalDetectionDisabled()) {
1291c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Service " << selected_service_->unique_name()
1292c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Portal detection is disabled; "
1293c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << "marking service online.";
1294d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart    SetServiceConnectedState(Service::kStateOnline);
1295d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart    return false;
1296d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart  }
1297d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart
1298d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart  if (selected_service_->IsPortalDetectionAuto() &&
1299d215af6f72d012f43057c34f17a12506baa21e66Paul Stewart      !manager_->IsPortalDetectionEnabled(technology())) {
130020088d860631a67c151a12783fbbee63c708792fPaul Stewart    // If portal detection is disabled for this technology, immediately set
130120088d860631a67c151a12783fbbee63c708792fPaul Stewart    // the service state to "Online".
1302c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1303c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Portal detection is disabled; "
1304c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << "marking service online.";
130520088d860631a67c151a12783fbbee63c708792fPaul Stewart    SetServiceConnectedState(Service::kStateOnline);
130620088d860631a67c151a12783fbbee63c708792fPaul Stewart    return false;
130720088d860631a67c151a12783fbbee63c708792fPaul Stewart  }
130820088d860631a67c151a12783fbbee63c708792fPaul Stewart
130920088d860631a67c151a12783fbbee63c708792fPaul Stewart  if (selected_service_->HasProxyConfig()) {
131020088d860631a67c151a12783fbbee63c708792fPaul Stewart    // Services with HTTP proxy configurations should not be checked by the
131120088d860631a67c151a12783fbbee63c708792fPaul Stewart    // connection manager, since we don't have the ability to evaluate
131220088d860631a67c151a12783fbbee63c708792fPaul Stewart    // arbitrary proxy configs and their possible credentials.
1313c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1314c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Service has proxy config; marking it online.";
131520088d860631a67c151a12783fbbee63c708792fPaul Stewart    SetServiceConnectedState(Service::kStateOnline);
131620088d860631a67c151a12783fbbee63c708792fPaul Stewart    return false;
131720088d860631a67c151a12783fbbee63c708792fPaul Stewart  }
131820088d860631a67c151a12783fbbee63c708792fPaul Stewart
131920088d860631a67c151a12783fbbee63c708792fPaul Stewart  portal_detector_.reset(new PortalDetector(connection_,
132020088d860631a67c151a12783fbbee63c708792fPaul Stewart                                            dispatcher_,
13213e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood                                            portal_detector_callback_));
132220088d860631a67c151a12783fbbee63c708792fPaul Stewart  if (!portal_detector_->Start(manager_->GetPortalCheckURL())) {
132320088d860631a67c151a12783fbbee63c708792fPaul Stewart    LOG(ERROR) << "Device " << FriendlyName()
132420088d860631a67c151a12783fbbee63c708792fPaul Stewart               << ": Portal detection failed to start: likely bad URL: "
132520088d860631a67c151a12783fbbee63c708792fPaul Stewart               << manager_->GetPortalCheckURL();
132620088d860631a67c151a12783fbbee63c708792fPaul Stewart    SetServiceConnectedState(Service::kStateOnline);
132720088d860631a67c151a12783fbbee63c708792fPaul Stewart    return false;
132820088d860631a67c151a12783fbbee63c708792fPaul Stewart  }
132920088d860631a67c151a12783fbbee63c708792fPaul Stewart
1330c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1331c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Portal detection has started.";
133220088d860631a67c151a12783fbbee63c708792fPaul Stewart  return true;
133320088d860631a67c151a12783fbbee63c708792fPaul Stewart}
133420088d860631a67c151a12783fbbee63c708792fPaul Stewart
133520088d860631a67c151a12783fbbee63c708792fPaul Stewartvoid Device::StopPortalDetection() {
1336c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1337c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Portal detection stopping.";
133820088d860631a67c151a12783fbbee63c708792fPaul Stewart  portal_detector_.reset();
133920088d860631a67c151a12783fbbee63c708792fPaul Stewart}
134020088d860631a67c151a12783fbbee63c708792fPaul Stewart
1341490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tanbool Device::StartConnectionDiagnosticsAfterPortalDetection(
1342490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan    const PortalDetector::Result& result) {
1343490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  connection_diagnostics_.reset(new ConnectionDiagnostics(
1344d1c7166402c414a851da721c2a3aaec713c25badSamuel Tan      connection_, dispatcher_, metrics_, manager_->device_info(),
1345490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan      connection_diagnostics_callback_));
1346490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  if (!connection_diagnostics_->StartAfterPortalDetection(
1347490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan      manager_->GetPortalCheckURL(), result)) {
1348490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan    LOG(ERROR) << "Device " << FriendlyName()
1349490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan               << ": Connection diagnostics failed to start: likely bad URL: "
1350490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan               << manager_->GetPortalCheckURL();
1351490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan    connection_diagnostics_.reset();
1352490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan    return false;
1353490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  }
1354490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan
1355490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  SLOG(this, 2) << "Device " << FriendlyName()
1356490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan                << ": Connection diagnostics has started.";
1357490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  return true;
1358490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan}
1359490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan
1360490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tanvoid Device::StopConnectionDiagnostics() {
1361490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  SLOG(this, 2) << "Device " << FriendlyName()
1362490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan                << ": Connection diagnostics stopping.";
1363490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan  connection_diagnostics_.reset();
1364490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan}
1365490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan
13666862b38f4691f6f927a5efffa3f587846ff96c72Rebecca Silbersteinbool Device::StartConnectivityTest() {
1367f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein  LOG(INFO) << "Device " << FriendlyName() << " starting connectivity test.";
13686862b38f4691f6f927a5efffa3f587846ff96c72Rebecca Silberstein
1369f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein  connection_tester_.reset(new ConnectionTester(connection_,
1370f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein                                                dispatcher_,
1371f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein                                                connection_tester_callback_));
1372f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein  connection_tester_->Start();
1373f4365a68767063e87dc7f68ff24b6c3955e88c5dRebecca Silberstein  return true;
13746862b38f4691f6f927a5efffa3f587846ff96c72Rebecca Silberstein}
13756862b38f4691f6f927a5efffa3f587846ff96c72Rebecca Silberstein
1376e8303eb267df8904623f16cba64e87df6e8a1563Paul Stewartvoid Device::StopConnectivityTest() {
1377c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1378c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Connectivity test stopping.";
1379e8303eb267df8904623f16cba64e87df6e8a1563Paul Stewart  connection_tester_.reset();
1380e8303eb267df8904623f16cba64e87df6e8a1563Paul Stewart}
1381e8303eb267df8904623f16cba64e87df6e8a1563Paul Stewart
1382a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::set_link_monitor(LinkMonitor* link_monitor) {
1383036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  link_monitor_.reset(link_monitor);
1384036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart}
1385036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart
1386036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewartbool Device::StartLinkMonitor() {
1387036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  if (!manager_->IsTechnologyLinkMonitorEnabled(technology())) {
1388c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1389c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Link Monitoring is disabled.";
1390036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart    return false;
1391036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  }
1392036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart
1393d49760e19d137f43df29e00265259d395b07994cPeter Qiu  if (selected_service_ && selected_service_->link_monitor_disabled()) {
1394c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1395c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Link Monitoring is disabled for the selected service";
1396d49760e19d137f43df29e00265259d395b07994cPeter Qiu    return false;
1397d49760e19d137f43df29e00265259d395b07994cPeter Qiu  }
1398d49760e19d137f43df29e00265259d395b07994cPeter Qiu
1399036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  if (!link_monitor()) {
1400036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart    set_link_monitor(
1401036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart      new LinkMonitor(
1402036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart          connection_, dispatcher_, metrics(), manager_->device_info(),
1403b5d124f4e789e7dd6afef6cc798b517650da5affPeter Qiu          Bind(&Device::OnLinkMonitorFailure, weak_ptr_factory_.GetWeakPtr()),
1404b5d124f4e789e7dd6afef6cc798b517650da5affPeter Qiu          Bind(&Device::OnLinkMonitorGatewayChange,
1405b5d124f4e789e7dd6afef6cc798b517650da5affPeter Qiu               weak_ptr_factory_.GetWeakPtr())));
1406036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  }
1407036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart
1408c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1409c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Link Monitor starting.";
1410036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  return link_monitor_->Start();
1411036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart}
1412036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart
1413036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewartvoid Device::StopLinkMonitor() {
1414c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1415c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Link Monitor stopping.";
1416036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  link_monitor_.reset();
1417036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart}
1418036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart
14198e1ad1684e2dd34619315c14f4b5312b93de0a83Peter Qiuvoid Device::OnUnreliableLink() {
1420a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  SLOG(this, 2) << "Device " << FriendlyName()
1421a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu                << ": Link is unreliable.";
1422a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  selected_service_->set_unreliable(true);
1423a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  reliable_link_callback_.Cancel();
14248e1ad1684e2dd34619315c14f4b5312b93de0a83Peter Qiu  metrics_->NotifyUnreliableLinkSignalStrength(
14258e1ad1684e2dd34619315c14f4b5312b93de0a83Peter Qiu      technology_, selected_service_->strength());
14268e1ad1684e2dd34619315c14f4b5312b93de0a83Peter Qiu}
14278e1ad1684e2dd34619315c14f4b5312b93de0a83Peter Qiu
1428a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiuvoid Device::OnReliableLink() {
1429a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  SLOG(this, 2) << "Device " << FriendlyName()
1430a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu                << ": Link is reliable.";
1431a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  selected_service_->set_unreliable(false);
1432a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  // TODO(zqiu): report signal strength to UMA.
1433a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu}
1434a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu
1435036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewartvoid Device::OnLinkMonitorFailure() {
1436c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1437c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Link Monitor indicates failure.";
1438a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  if (!selected_service_) {
1439a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu    return;
1440a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  }
1441a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu
1442a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  time_t now;
1443a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  time_->GetSecondsBoottime(&now);
1444a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu
1445a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu  if (last_link_monitor_failed_time_ != 0 &&
1446a388fdb2e74717ba2440a605f208647dd7cd3e06Peter Qiu      now - last_link_monitor_failed_time_ < kLinkUnreliableThresholdSeconds) {
14478e1ad1684e2dd34619315c14f4b5312b93de0a83Peter Qiu    OnUnreliableLink();
1448a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  }
1449a0572036bd4374282fb26e861e7a242fe55a54a3Peter Qiu  last_link_monitor_failed_time_ = now;
1450036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart}
1451036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart
14529d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiuvoid Device::OnLinkMonitorGatewayChange() {
14539d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu  string gateway_mac = link_monitor()->gateway_mac_address().HexEncode();
14549d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu  int connection_id = manager_->CalcConnectionId(
14559d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu      ipconfig_->properties().gateway, gateway_mac);
14569d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu
14579d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu  CHECK(selected_service_);
14589d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu  selected_service_->set_connection_id(connection_id);
14599d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu
14609d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu  manager_->ReportServicesOnSameNetwork(connection_id);
14619d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu}
14629d58193108f55edf0f06cd54f44464da633cb8aaPeter Qiu
14636f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiubool Device::StartDNSTest(
1464a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const vector<string>& dns_servers,
14656f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu    bool retry_until_success,
1466a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const Callback<void(const DNSServerTester::Status)>& callback) {
14676f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  if (dns_server_tester_.get()) {
14686f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu    LOG(ERROR) << FriendlyName() << ": "
14696f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu               << "Failed to start DNS Test: current test still running";
14706f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu    return false;
1471b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu  }
1472b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu
14736f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  dns_server_tester_.reset(new DNSServerTester(connection_,
14746f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                                               dispatcher_,
14756f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                                               dns_servers,
14766f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                                               retry_until_success,
14776f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                                               callback));
14786f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  dns_server_tester_->Start();
14796f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  return true;
14806f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu}
14816f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu
14826f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiuvoid Device::StopDNSTest() {
14836f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  dns_server_tester_.reset();
1484b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu}
1485b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu
1486d670d03b90f4372bb085c7d2a128c6025e998d78Peter Qiuvoid Device::FallbackDNSResultCallback(const DNSServerTester::Status status) {
14876f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  StopDNSTest();
1488f18e7717c642dcfd6b4dbe1f01f50e2d9671f5cePeter Qiu  int result = Metrics::kFallbackDNSTestResultFailure;
1489d670d03b90f4372bb085c7d2a128c6025e998d78Peter Qiu  if (status == DNSServerTester::kStatusSuccess) {
1490f18e7717c642dcfd6b4dbe1f01f50e2d9671f5cePeter Qiu    result = Metrics::kFallbackDNSTestResultSuccess;
1491a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu
1492a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu    // Switch to fallback DNS server if service is configured to allow DNS
1493a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu    // fallback.
1494a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu    CHECK(selected_service_);
1495a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu    if (selected_service_->is_dns_auto_fallback_allowed()) {
14966f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu      LOG(INFO) << "Device " << FriendlyName()
14976f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                << ": Switching to fallback DNS servers.";
14986f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu      // Save the DNS servers from ipconfig.
14996f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu      config_dns_servers_ = ipconfig_->properties().dns_servers;
1500a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu      SwitchDNSServers(vector<string>(std::begin(kFallbackDnsServers),
1501a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu                                      std::end(kFallbackDnsServers)));
15026f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu      // Start DNS test for configured DNS servers.
15036f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu      StartDNSTest(config_dns_servers_,
15046f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                   true,
15056f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                   Bind(&Device::ConfigDNSResultCallback,
15066f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                        weak_ptr_factory_.GetWeakPtr()));
1507a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu    }
1508b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu  }
1509f18e7717c642dcfd6b4dbe1f01f50e2d9671f5cePeter Qiu  metrics()->NotifyFallbackDNSTestResult(technology_, result);
15106f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu}
15116f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu
15126f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiuvoid Device::ConfigDNSResultCallback(const DNSServerTester::Status status) {
15136f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  StopDNSTest();
15146f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  // DNS test failed to start due to internal error.
15156f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  if (status == DNSServerTester::kStatusFailure) {
15166f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu    return;
15176f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  }
15186f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu
15196f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  // Switch back to the configured DNS servers.
15206f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  LOG(INFO) << "Device " << FriendlyName()
15216f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu            << ": Switching back to configured DNS servers.";
15226f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  SwitchDNSServers(config_dns_servers_);
1523b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu}
1524b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu
1525a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::SwitchDNSServers(const vector<string>& dns_servers) {
1526a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  CHECK(ipconfig_);
1527a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  CHECK(connection_);
1528a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  // Push new DNS servers setting to the IP config object.
1529a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  ipconfig_->UpdateDNSServers(dns_servers);
1530a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  // Push new DNS servers setting to the current connection, so the resolver
1531a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  // will be updated to use the new DNS servers.
1532a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  connection_->UpdateDNSServers(dns_servers);
1533a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  // Allow the service to notify Chrome of ipconfig changes.
1534a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu  selected_service_->NotifyIPConfigChanges();
15356f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  // Restart the portal detection with the new DNS setting.
15366f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu  RestartPortalDetection();
1537a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu}
1538a89154bfedfd8872242083ffe4f084fdc774c078Peter Qiu
1539a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::set_traffic_monitor(TrafficMonitor* traffic_monitor) {
1540dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  traffic_monitor_.reset(traffic_monitor);
1541dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu}
1542dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
1543a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::TimeToNextDHCPLeaseRenewal(uint32_t* result) {
1544787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  if (!ipconfig() && !ip6config()) {
1545787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    return false;
1546787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  }
1547787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  uint32_t time_to_ipv4_lease_expiry = UINT32_MAX;
1548787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  uint32_t time_to_ipv6_lease_expiry = UINT32_MAX;
1549787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  if (ipconfig()) {
1550787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    ipconfig()->TimeToLeaseExpiry(&time_to_ipv4_lease_expiry);
1551787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  }
1552787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  if (ip6config()) {
1553787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan    ip6config()->TimeToLeaseExpiry(&time_to_ipv6_lease_expiry);
1554787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  }
1555787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  *result = std::min(time_to_ipv4_lease_expiry, time_to_ipv6_lease_expiry);
1556787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan  return true;
1557787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan}
1558787a1cebf2452c14bf392ab99902e686ea4a6fb4Samuel Tan
1559dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiubool Device::IsTrafficMonitorEnabled() const {
1560dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  return false;
1561dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu}
1562dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
1563dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiuvoid Device::StartTrafficMonitor() {
1564dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  // Return if traffic monitor is not enabled for this device.
1565dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  if (!IsTrafficMonitorEnabled()) {
1566dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    return;
1567dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  }
1568dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
1569c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1570c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Traffic Monitor starting.";
1571dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  if (!traffic_monitor_.get()) {
1572dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    traffic_monitor_.reset(new TrafficMonitor(this, dispatcher_));
1573dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    traffic_monitor_->set_network_problem_detected_callback(
1574dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu        Bind(&Device::OnEncounterNetworkProblem,
1575dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu             weak_ptr_factory_.GetWeakPtr()));
1576dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  }
1577dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  traffic_monitor_->Start();
1578dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu}
1579dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
1580dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiuvoid Device::StopTrafficMonitor() {
1581dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  // Return if traffic monitor is not enabled for this device.
1582dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  if (!IsTrafficMonitorEnabled()) {
1583dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    return;
1584dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  }
1585dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
1586dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  if (traffic_monitor_.get()) {
1587c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1588c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Traffic Monitor stopping.";
1589dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    traffic_monitor_->Stop();
1590dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  }
1591dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  traffic_monitor_.reset();
1592dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu}
1593dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
1594dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiuvoid Device::OnEncounterNetworkProblem(int reason) {
1595dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  int metric_code;
1596dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  switch (reason) {
1597dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    case TrafficMonitor::kNetworkProblemCongestedTxQueue:
1598dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu      metric_code = Metrics::kNetworkProblemCongestedTCPTxQueue;
1599dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu      break;
1600dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    case TrafficMonitor::kNetworkProblemDNSFailure:
1601dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu      metric_code = Metrics::kNetworkProblemDNSFailure;
1602dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu      break;
1603dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu    default:
1604dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu      LOG(ERROR) << "Invalid network problem code: " << reason;
1605dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu      return;
1606dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  }
1607dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
1608dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  metrics()->NotifyNetworkProblemDetected(technology_, metric_code);
1609dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  // Stop the traffic monitor, only report the first network problem detected
1610dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  // on the connection for now.
1611dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu  StopTrafficMonitor();
1612dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu}
1613dc335f81a9d0ffe8efd02a96d3cd17399a06e61ePeter Qiu
161420088d860631a67c151a12783fbbee63c708792fPaul Stewartvoid Device::SetServiceConnectedState(Service::ConnectState state) {
161520088d860631a67c151a12783fbbee63c708792fPaul Stewart  DCHECK(selected_service_.get());
161620088d860631a67c151a12783fbbee63c708792fPaul Stewart
161720088d860631a67c151a12783fbbee63c708792fPaul Stewart  if (!selected_service_.get()) {
161820088d860631a67c151a12783fbbee63c708792fPaul Stewart    LOG(ERROR) << FriendlyName() << ": "
161920088d860631a67c151a12783fbbee63c708792fPaul Stewart               << "Portal detection completed but no selected service exists!";
162020088d860631a67c151a12783fbbee63c708792fPaul Stewart    return;
162120088d860631a67c151a12783fbbee63c708792fPaul Stewart  }
162220088d860631a67c151a12783fbbee63c708792fPaul Stewart
162320088d860631a67c151a12783fbbee63c708792fPaul Stewart  if (!selected_service_->IsConnected()) {
162420088d860631a67c151a12783fbbee63c708792fPaul Stewart    LOG(ERROR) << FriendlyName() << ": "
162520088d860631a67c151a12783fbbee63c708792fPaul Stewart               << "Portal detection completed but selected service "
1626457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov               << selected_service_->unique_name()
162720088d860631a67c151a12783fbbee63c708792fPaul Stewart               << " is in non-connected state.";
162820088d860631a67c151a12783fbbee63c708792fPaul Stewart    return;
162920088d860631a67c151a12783fbbee63c708792fPaul Stewart  }
163020088d860631a67c151a12783fbbee63c708792fPaul Stewart
1631c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  if (state == Service::kStatePortal && connection_->is_default() &&
1632c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart      manager_->GetPortalCheckInterval() != 0) {
1633c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    CHECK(portal_detector_.get());
1634c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    if (!portal_detector_->StartAfterDelay(
1635c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart            manager_->GetPortalCheckURL(),
1636c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart            manager_->GetPortalCheckInterval())) {
1637c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart      LOG(ERROR) << "Device " << FriendlyName()
1638c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart                 << ": Portal detection failed to restart: likely bad URL: "
1639c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart                 << manager_->GetPortalCheckURL();
1640c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart      SetServiceState(Service::kStateOnline);
1641c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart      portal_detector_.reset();
1642c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart      return;
1643c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    }
1644c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1645c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Portal detection retrying.";
1646c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  } else {
1647c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1648c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Portal will not retry.";
1649c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart    portal_detector_.reset();
1650c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  }
1651c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
165220088d860631a67c151a12783fbbee63c708792fPaul Stewart  SetServiceState(state);
165320088d860631a67c151a12783fbbee63c708792fPaul Stewart}
165420088d860631a67c151a12783fbbee63c708792fPaul Stewart
1655a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::PortalDetectorCallback(const PortalDetector::Result& result) {
165620088d860631a67c151a12783fbbee63c708792fPaul Stewart  if (!result.final) {
1657c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Device " << FriendlyName()
1658c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ": Received non-final status: "
1659c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << ConnectivityTrial::StatusToString(
1660c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                      result.trial_result.status);
166120088d860631a67c151a12783fbbee63c708792fPaul Stewart    return;
166220088d860631a67c151a12783fbbee63c708792fPaul Stewart  }
166320088d860631a67c151a12783fbbee63c708792fPaul Stewart
1664c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << FriendlyName()
1665c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ": Received final status: "
1666c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ConnectivityTrial::StatusToString(
1667c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    result.trial_result.status);
166820088d860631a67c151a12783fbbee63c708792fPaul Stewart
166985e050b4923878a57aec1415314d2b39ff233e00Thieu Le  portal_attempts_to_online_ += result.num_attempts;
167085e050b4923878a57aec1415314d2b39ff233e00Thieu Le
1671b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu  int portal_status = Metrics::PortalDetectionResultToEnum(result);
167285e050b4923878a57aec1415314d2b39ff233e00Thieu Le  metrics()->SendEnumToUMA(
1673132e96ff1c3dade1b08cdae82b0f4ed27a9a45d0mukesh agrawal      metrics()->GetFullMetricName(Metrics::kMetricPortalResultSuffix,
1674132e96ff1c3dade1b08cdae82b0f4ed27a9a45d0mukesh agrawal                                   technology()),
1675b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu      portal_status,
167685e050b4923878a57aec1415314d2b39ff233e00Thieu Le      Metrics::kPortalResultMax);
167785e050b4923878a57aec1415314d2b39ff233e00Thieu Le
16783d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  if (result.trial_result.status == ConnectivityTrial::kStatusSuccess) {
167920088d860631a67c151a12783fbbee63c708792fPaul Stewart    SetServiceConnectedState(Service::kStateOnline);
168085e050b4923878a57aec1415314d2b39ff233e00Thieu Le
168185e050b4923878a57aec1415314d2b39ff233e00Thieu Le    metrics()->SendToUMA(
168285e050b4923878a57aec1415314d2b39ff233e00Thieu Le        metrics()->GetFullMetricName(
1683132e96ff1c3dade1b08cdae82b0f4ed27a9a45d0mukesh agrawal            Metrics::kMetricPortalAttemptsToOnlineSuffix, technology()),
168485e050b4923878a57aec1415314d2b39ff233e00Thieu Le        portal_attempts_to_online_,
168585e050b4923878a57aec1415314d2b39ff233e00Thieu Le        Metrics::kMetricPortalAttemptsToOnlineMin,
168685e050b4923878a57aec1415314d2b39ff233e00Thieu Le        Metrics::kMetricPortalAttemptsToOnlineMax,
168785e050b4923878a57aec1415314d2b39ff233e00Thieu Le        Metrics::kMetricPortalAttemptsToOnlineNumBuckets);
168820088d860631a67c151a12783fbbee63c708792fPaul Stewart  } else {
16899b83c897f8e197ff7846e4fe7cec1d83d54e7b7bPeter Qiu    // Set failure phase and status.
16909b83c897f8e197ff7846e4fe7cec1d83d54e7b7bPeter Qiu    if (selected_service_.get()) {
16919b83c897f8e197ff7846e4fe7cec1d83d54e7b7bPeter Qiu      selected_service_->SetPortalDetectionFailure(
16923d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          ConnectivityTrial::PhaseToString(result.trial_result.phase),
16933d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          ConnectivityTrial::StatusToString(result.trial_result.status));
16949b83c897f8e197ff7846e4fe7cec1d83d54e7b7bPeter Qiu    }
169520088d860631a67c151a12783fbbee63c708792fPaul Stewart    SetServiceConnectedState(Service::kStatePortal);
169685e050b4923878a57aec1415314d2b39ff233e00Thieu Le
169785e050b4923878a57aec1415314d2b39ff233e00Thieu Le    metrics()->SendToUMA(
169885e050b4923878a57aec1415314d2b39ff233e00Thieu Le        metrics()->GetFullMetricName(
1699132e96ff1c3dade1b08cdae82b0f4ed27a9a45d0mukesh agrawal            Metrics::kMetricPortalAttemptsSuffix, technology()),
170085e050b4923878a57aec1415314d2b39ff233e00Thieu Le        result.num_attempts,
170185e050b4923878a57aec1415314d2b39ff233e00Thieu Le        Metrics::kMetricPortalAttemptsMin,
170285e050b4923878a57aec1415314d2b39ff233e00Thieu Le        Metrics::kMetricPortalAttemptsMax,
170385e050b4923878a57aec1415314d2b39ff233e00Thieu Le        Metrics::kMetricPortalAttemptsNumBuckets);
1704b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu
1705490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan    StartConnectionDiagnosticsAfterPortalDetection(result);
1706490063ebd172dbaf5328c682f7338b2c1f6331dfSamuel Tan
1707b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    // TODO(zqiu): Only support fallback DNS server for IPv4 for now.
1708b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    if (connection_->IsIPv6()) {
1709b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu      return;
1710b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu    }
1711b25083f4ec00167ceed71a7f961e3f1435dbe070Peter Qiu
1712b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu    // Perform fallback DNS test if the portal failure is DNS related.
1713b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu    // The test will send a  DNS request to Google's DNS server to determine
1714b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu    // if the DNS failure is due to bad DNS server settings.
1715b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu    if ((portal_status == Metrics::kPortalResultDNSFailure) ||
1716b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu        (portal_status == Metrics::kPortalResultDNSTimeout)) {
17176f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu      StartDNSTest(vector<string>(std::begin(kFallbackDnsServers),
17186f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                                  std::end(kFallbackDnsServers)),
17196f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                   false,
17206f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                   Bind(&Device::FallbackDNSResultCallback,
17216f5618beb7e382b1b122e7a63b63f1bca7723417Peter Qiu                        weak_ptr_factory_.GetWeakPtr()));
1722b9256f3d485e4c6c5c301a0aa00554059473b41dPeter Qiu    }
172320088d860631a67c151a12783fbbee63c708792fPaul Stewart  }
172420088d860631a67c151a12783fbbee63c708792fPaul Stewart}
172520088d860631a67c151a12783fbbee63c708792fPaul Stewart
1726a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartstring Device::GetSelectedServiceRpcIdentifier(Error* /*error*/) {
1727674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley  if (!selected_service_) {
1728674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley    return "/";
1729674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley  }
1730674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley  return selected_service_->GetRpcIdentifier();
1731674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley}
1732674598d8b8fd78424bf1b0d4e18ec3bc57cf56cdChristopher Wiley
1733a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvector<string> Device::AvailableIPConfigs(Error* /*error*/) {
1734d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  vector<string> ipconfigs;
1735d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  if (ipconfig_) {
1736d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    ipconfigs.push_back(ipconfig_->GetRpcIdentifier());
1737d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  }
1738d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  if (ip6config_) {
1739d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart    ipconfigs.push_back(ip6config_->GetRpcIdentifier());
174008afdffc182c7f04a8acdbb63240585069af8040Jason Glasgow  }
1741d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  if (dhcpv6_config_) {
1742d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu    ipconfigs.push_back(dhcpv6_config_->GetRpcIdentifier());
1743d48fa0c5531e2102d4f537e81b9f92afc2d60955Peter Qiu  }
1744d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  return ipconfigs;
17454e85161f12699d8eb2116ae24766676ed8227a71Chris Masone}
17464e85161f12699d8eb2116ae24766676ed8227a71Chris Masone
1747a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartuint64_t Device::GetLinkMonitorResponseTime(Error* error) {
1748036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  if (!link_monitor_.get()) {
1749036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart    // It is not strictly an error that the link monitor does not
1750036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart    // exist, but returning an error here allows the GetProperties
1751036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart    // call in our Adaptor to omit this parameter.
1752036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart    error->Populate(Error::kNotFound, "Device is not running LinkMonitor");
1753036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart    return 0;
1754036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  }
1755036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart  return link_monitor_->GetResponseTimeMilliseconds();
1756036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart}
1757036dba0c6641acdbe02d52260c6fa6dca84b1af2Paul Stewart
17587fab89734d88724a288e96a9996b15548c5294c7Ben Chanuint64_t Device::GetReceiveByteCount() {
17597fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint64_t rx_byte_count = 0, tx_byte_count = 0;
17606ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  manager_->device_info()->GetByteCounts(
17616ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      interface_index_, &rx_byte_count, &tx_byte_count);
17626ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  return rx_byte_count - receive_byte_offset_;
17636ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart}
17646ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
17657fab89734d88724a288e96a9996b15548c5294c7Ben Chanuint64_t Device::GetTransmitByteCount() {
17667fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint64_t rx_byte_count = 0, tx_byte_count = 0;
17676ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  manager_->device_info()->GetByteCounts(
17686ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart      interface_index_, &rx_byte_count, &tx_byte_count);
17696ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart  return tx_byte_count - transmit_byte_offset_;
17706ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart}
17716ff27f578d3a4474d82dc3881441fc365e813ec9Paul Stewart
1772a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartuint64_t Device::GetReceiveByteCountProperty(Error* /*error*/) {
1773b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan  return GetReceiveByteCount();
1774b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan}
1775b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan
1776a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartuint64_t Device::GetTransmitByteCountProperty(Error* /*error*/) {
1777b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan  return GetTransmitByteCount();
1778b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan}
1779b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan
17807fce52c4afdc5e73a9e740dc9b90f1e61ae8cea4Eric Shienbroodbool Device::IsUnderlyingDeviceEnabled() const {
17817fce52c4afdc5e73a9e740dc9b90f1e61ae8cea4Eric Shienbrood  return false;
17827fce52c4afdc5e73a9e740dc9b90f1e61ae8cea4Eric Shienbrood}
17837fce52c4afdc5e73a9e740dc9b90f1e61ae8cea4Eric Shienbrood
17849a24553461df7036755060423f90804011612249Eric Shienbrood// callback
1785a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::OnEnabledStateChanged(const ResultCallback& callback,
1786a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                   const Error& error) {
1787c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__
1788c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " (target: " << enabled_pending_ << ","
1789c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " success: " << error.IsSuccess() << ")"
1790c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " on " << link_name_;
17919a24553461df7036755060423f90804011612249Eric Shienbrood  if (error.IsSuccess()) {
17929a24553461df7036755060423f90804011612249Eric Shienbrood    enabled_ = enabled_pending_;
17939a24553461df7036755060423f90804011612249Eric Shienbrood    manager_->UpdateEnabledTechnologies();
1794923a5025a5e1138b052cbeffa60ea387d479696fBen Chan    adaptor_->EmitBoolChanged(kPoweredProperty, enabled_);
17959a24553461df7036755060423f90804011612249Eric Shienbrood  }
1796baeefdf544bfcfe2895e4e15c348db3f7ce4d45bGary Morain  enabled_pending_ = enabled_;
17979a24553461df7036755060423f90804011612249Eric Shienbrood  if (!callback.is_null())
17989a24553461df7036755060423f90804011612249Eric Shienbrood    callback.Run(error);
17999a24553461df7036755060423f90804011612249Eric Shienbrood}
18009a24553461df7036755060423f90804011612249Eric Shienbrood
18019a24553461df7036755060423f90804011612249Eric Shienbroodvoid Device::SetEnabled(bool enable) {
1802c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(" << enable << ")";
18034a4907904affddc3cf6f88ce3b4662d66a9e18ebJason Glasgow  Error error;
180428185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal  SetEnabledChecked(enable, false, &error, ResultCallback());
18058bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray
18068bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray  // SetEnabledInternal might fail here if there is an unfinished enable or
18078bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray  // disable operation. Don't log error in this case, as this method is only
18088bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray  // called when the underlying device is already in the target state and the
18098bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray  // pending operation should eventually bring the device to the expected
18108bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray  // state.
18118bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray  LOG_IF(ERROR,
18128bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray         error.IsFailure() &&
18138bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray         !error.IsOngoing() &&
18148bf6a5c1b559d57fe448132cfff5795a14cf9685Arman Uguray         error.type() != Error::kInProgress)
18154a4907904affddc3cf6f88ce3b4662d66a9e18ebJason Glasgow      << "Enabled failed, but no way to report the failure.";
18169a24553461df7036755060423f90804011612249Eric Shienbrood}
18179a24553461df7036755060423f90804011612249Eric Shienbrood
18189f3dcf80a84c07701b7c224fca5ed637c966fa3eBen Chanvoid Device::SetEnabledNonPersistent(bool enable,
1819a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                     Error* error,
1820a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                     const ResultCallback& callback) {
182128185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal  SetEnabledChecked(enable, false, error, callback);
18229f3dcf80a84c07701b7c224fca5ed637c966fa3eBen Chan}
18239f3dcf80a84c07701b7c224fca5ed637c966fa3eBen Chan
18249a24553461df7036755060423f90804011612249Eric Shienbroodvoid Device::SetEnabledPersistent(bool enable,
1825a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                  Error* error,
1826a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                  const ResultCallback& callback) {
182728185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal  SetEnabledChecked(enable, true, error, callback);
18289a24553461df7036755060423f90804011612249Eric Shienbrood}
18299a24553461df7036755060423f90804011612249Eric Shienbrood
183028185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawalvoid Device::SetEnabledChecked(bool enable,
183128185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal                               bool persist,
1832a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                               Error* error,
1833a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                               const ResultCallback& callback) {
18344a4907904affddc3cf6f88ce3b4662d66a9e18ebJason Glasgow  DCHECK(error);
1835c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Device " << link_name_ << " "
1836c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << (enable ? "starting" : "stopping");
1837ff6be29bd74abd31640abcf9ad4332e0a9657196Paul Stewart  if (enable && manager_->IsTechnologyProhibited(technology())) {
1838ff6be29bd74abd31640abcf9ad4332e0a9657196Paul Stewart    error->Populate(Error::kPermissionDenied, "The " +
1839ff6be29bd74abd31640abcf9ad4332e0a9657196Paul Stewart                    Technology::NameFromIdentifier(technology()) +
1840ff6be29bd74abd31640abcf9ad4332e0a9657196Paul Stewart                    " technology is prohibited");
1841ff6be29bd74abd31640abcf9ad4332e0a9657196Paul Stewart    return;
1842ff6be29bd74abd31640abcf9ad4332e0a9657196Paul Stewart  }
1843ff6be29bd74abd31640abcf9ad4332e0a9657196Paul Stewart
18449a24553461df7036755060423f90804011612249Eric Shienbrood  if (enable == enabled_) {
18452f352e606bbe6074eeca93eb457837e501420be7Arman Uguray    if (enable != enabled_pending_ && persist) {
18462f352e606bbe6074eeca93eb457837e501420be7Arman Uguray      // Return an error, as there is an ongoing operation to achieve the
18472f352e606bbe6074eeca93eb457837e501420be7Arman Uguray      // opposite.
18482f352e606bbe6074eeca93eb457837e501420be7Arman Uguray      Error::PopulateAndLog(
184934f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart          FROM_HERE, error, Error::kOperationFailed,
18502f352e606bbe6074eeca93eb457837e501420be7Arman Uguray          enable ? "Cannot enable while the device is disabling." :
18512f352e606bbe6074eeca93eb457837e501420be7Arman Uguray                   "Cannot disable while the device is enabling.");
18522f352e606bbe6074eeca93eb457837e501420be7Arman Uguray      return;
18532f352e606bbe6074eeca93eb457837e501420be7Arman Uguray    }
185428185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal    LOG(INFO) << "Already in desired enable state.";
18554a4907904affddc3cf6f88ce3b4662d66a9e18ebJason Glasgow    error->Reset();
18569a24553461df7036755060423f90804011612249Eric Shienbrood    return;
18579a24553461df7036755060423f90804011612249Eric Shienbrood  }
18589a24553461df7036755060423f90804011612249Eric Shienbrood
18599a24553461df7036755060423f90804011612249Eric Shienbrood  if (enabled_pending_ == enable) {
186034f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart    Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
18614a4907904affddc3cf6f88ce3b4662d66a9e18ebJason Glasgow                          "Enable operation already in progress");
18629a24553461df7036755060423f90804011612249Eric Shienbrood    return;
18639a24553461df7036755060423f90804011612249Eric Shienbrood  }
18649a24553461df7036755060423f90804011612249Eric Shienbrood
18659a24553461df7036755060423f90804011612249Eric Shienbrood  if (persist) {
18669a24553461df7036755060423f90804011612249Eric Shienbrood    enabled_persistent_ = enable;
1867e7c6ad35cafed32a0fd1390487c74e66eae1961dDarin Petkov    manager_->UpdateDevice(this);
18689a24553461df7036755060423f90804011612249Eric Shienbrood  }
18699a24553461df7036755060423f90804011612249Eric Shienbrood
187028185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal  SetEnabledUnchecked(enable, error, callback);
187128185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal}
187228185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal
1873a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid Device::SetEnabledUnchecked(bool enable, Error* error,
1874a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                 const ResultCallback& on_enable_complete) {
18759a24553461df7036755060423f90804011612249Eric Shienbrood  enabled_pending_ = enable;
187628185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal  EnabledStateChangedCallback chained_callback =
18779a24553461df7036755060423f90804011612249Eric Shienbrood      Bind(&Device::OnEnabledStateChanged,
187828185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal           weak_ptr_factory_.GetWeakPtr(), on_enable_complete);
18799a24553461df7036755060423f90804011612249Eric Shienbrood  if (enable) {
18809a24553461df7036755060423f90804011612249Eric Shienbrood    running_ = true;
188128185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal    Start(error, chained_callback);
18829a24553461df7036755060423f90804011612249Eric Shienbrood  } else {
18839a24553461df7036755060423f90804011612249Eric Shienbrood    running_ = false;
18849a24553461df7036755060423f90804011612249Eric Shienbrood    DestroyIPConfig();         // breaks a reference cycle
1885cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan    SelectService(nullptr);    // breaks a reference cycle
18869a24553461df7036755060423f90804011612249Eric Shienbrood    rtnl_handler_->SetInterfaceFlags(interface_index(), 0, IFF_UP);
1887c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << "Device " << link_name_ << " ipconfig_ "
1888c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << (ipconfig_ ? "is set." : "is not set.");
1889c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << "Device " << link_name_ << " ip6config_ "
1890c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << (ip6config_ ? "is set." : "is not set.");
1891c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << "Device " << link_name_ << " connection_ "
1892c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << (connection_ ? "is set." : "is not set.");
1893c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 3) << "Device " << link_name_ << " selected_service_ "
1894c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << (selected_service_ ? "is set." : "is not set.");
189528185511575e3a670c6dc2499b33ef992e4fc2f0mukesh agrawal    Stop(error, chained_callback);
18969a24553461df7036755060423f90804011612249Eric Shienbrood  }
18979a24553461df7036755060423f90804011612249Eric Shienbrood}
18989a24553461df7036755060423f90804011612249Eric Shienbrood
1899d4f26486b237fae831d4b682481de785fc99c66ePaul Stewartvoid Device::UpdateIPConfigsProperty() {
1900d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart  adaptor_->EmitRpcIdentifierArrayChanged(
1901cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan      kIPConfigsProperty, AvailableIPConfigs(nullptr));
1902d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart}
1903d4f26486b237fae831d4b682481de785fc99c66ePaul Stewart
1904a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool Device::ResolvePeerMacAddress(const string& input,
1905a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                   string* output,
1906a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                   Error* error) {
190762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  if (!MakeHardwareAddressFromString(input).empty()) {
190862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    // Input is already a MAC address.
190962abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    *output = input;
191062abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    return true;
191162abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  }
191262abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu
191362abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  IPAddress ip_address(IPAddress::kFamilyIPv4);
191462abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  if (!ip_address.SetAddressFromString(input)) {
191562abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
191662abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                          "Peer is neither an IP Address nor a MAC address");
191762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    return false;
191862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  }
191962abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu
192062abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  // Peer address was specified as an IP address which we need to resolve.
1921a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const DeviceInfo* device_info = manager()->device_info();
192262abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  if (!device_info->HasDirectConnectivityTo(interface_index_, ip_address)) {
192362abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
192462abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                          "IP address is not local to this interface");
192562abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    return false;
192662abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  }
192762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu
192862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  ByteString mac_address;
192962abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  if (device_info->GetMACAddressOfPeer(interface_index_,
193062abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                                       ip_address,
193162abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                                       &mac_address)) {
193262abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    *output = MakeStringFromHardwareAddress(
193362abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu        vector<uint8_t>(mac_address.GetConstData(),
193462abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                        mac_address.GetConstData() +
193562abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                        mac_address.GetLength()));
193662abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    SLOG(this, 2) << "ARP cache lookup returned peer: " << *output;
193762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    return true;
193862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  }
193962abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu
1940f66080eb8e8826128d6ad57cce3e9722c8f5a31fSamuel Tan  if (!Icmp().TransmitEchoRequest(ip_address, 1, 1)) {
194162abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed,
194262abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                          "Failed to send ICMP request to peer to setup ARP");
194362abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  } else {
194462abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    // ARP request was transmitted successfully, address resolution is still
194562abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    // pending.
194662abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    error->Populate(Error::kInProgress,
194762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                    "Peer MAC address was not found in the ARP cache, "
194862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                    "but an ARP request was sent to find it.  "
194962abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                    "Please try again.");
195062abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  }
195162abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  return false;
195262abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu}
195362abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu
195462abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu// static
195562abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiuvector<uint8_t> Device::MakeHardwareAddressFromString(
1956a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& address_string) {
195762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  string address_nosep;
195862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  base::RemoveChars(address_string, ":", &address_nosep);
195962abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  vector<uint8_t> address_bytes;
196062abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  base::HexStringToBytes(address_nosep, &address_bytes);
196162abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  if (address_bytes.size() != kHardwareAddressLength) {
196262abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu    return vector<uint8_t>();
196362abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  }
196462abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  return address_bytes;
196562abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu}
196662abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu
196762abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu// static
196862abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiustring Device::MakeStringFromHardwareAddress(
1969a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const vector<uint8_t>& address_bytes) {
197062abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  CHECK_EQ(kHardwareAddressLength, address_bytes.size());
197162abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu  return StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
197262abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                      address_bytes[0], address_bytes[1], address_bytes[2],
197362abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu                      address_bytes[3], address_bytes[4], address_bytes[5]);
197462abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu}
197562abf31989c52dc1e4ee5aae71664ba81d6fe2dbPeter Qiu
19768ff81329524eb3af0d8e7b2642a4a4c262d6b4fdNingyuan Wangbool Device::RequestRoam(const std::string& addr, Error* error) {
19778ff81329524eb3af0d8e7b2642a4a4c262d6b4fdNingyuan Wang  return false;
19788ff81329524eb3af0d8e7b2642a4a4c262d6b4fdNingyuan Wang}
19798ff81329524eb3af0d8e7b2642a4a4c262d6b4fdNingyuan Wang
198075897df1154ac38b7a4512a687241ad6a197ee40Paul Stewart}  // namespace shill
1981