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//
160af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
17cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include "shill/device_info.h"
180af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
190af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <arpa/inet.h>
20cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <fcntl.h>
21cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <linux/if_tun.h>
220af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <linux/netlink.h>
230af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <linux/rtnetlink.h>
24cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <net/if.h>
25cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <net/if_arp.h>
26cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <netinet/ether.h>
27cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <string.h>
28cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <sys/ioctl.h>
29cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <sys/socket.h>
30cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <time.h>
31cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <unistd.h>
32cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
330af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <string>
340af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
353e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/bind.h>
36a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/files/file_enumerator.h>
3711c213f3cf64f27a0e42ee6da95e98bd1d4b3202Ben Chan#include <base/files/file_util.h>
386fbf64f493a9aae7d743888039c61a57386203dbBen Chan#include <base/files/scoped_file.h>
393e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/stl_util.h>
40a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_number_conversions.h>
41a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_util.h>
42a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/stringprintf.h>
430af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
440af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include "shill/control_interface.h"
459be4a9d1e87d64f850f15061123b2a4334477fa2Chris Masone#include "shill/device.h"
46a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart#include "shill/device_stub.h"
4787602518c59af2f9e8288d81a1f877dd80f24433Ben Chan#include "shill/ethernet/ethernet.h"
4887602518c59af2f9e8288d81a1f877dd80f24433Ben Chan#include "shill/ethernet/virtio_ethernet.h"
49b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h"
50b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart#include "shill/manager.h"
518d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/ndisc.h"
528d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_handler.h"
538d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_listener.h"
548d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/rtnl_message.h"
558d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/shill_time.h"
568d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/sockets.h"
578c116a90d3a3536430b808b15e73275060918434Paul Stewart#include "shill/routing_table.h"
58487b8bfc46a91e29bb23aaf3c59cfe67033bfc8bChris Masone#include "shill/service.h"
592240e8c03451c6b6f21eb8944d8a1c0747ac10b3Ben Chan#include "shill/vpn/vpn_provider.h"
601a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu
611a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#if !defined(DISABLE_WIFI)
621a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#include "shill/net/netlink_attribute.h"
631a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#include "shill/net/netlink_manager.h"
641a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#include "shill/net/nl80211_message.h"
65d6a8b519e3057f52313e502f502a4819a942e089Ben Chan#include "shill/wifi/wifi.h"
661a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#endif  // DISABLE_WIFI
670af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
683e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Bind;
69a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chanusing base::FileEnumerator;
700e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulkusing base::FilePath;
718f1c835d879f82261a08257eb6f9677e6be51fdaThieu Leusing base::StringPrintf;
723e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Unretained;
73e6193c042652831cac90c3bbf2233877754b1eefDarin Petkovusing std::map;
74050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartusing std::set;
750af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewartusing std::string;
769a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartusing std::vector;
770af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
780af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewartnamespace shill {
79b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
80c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinnamespace Logging {
81c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinstatic auto kModuleLogScope = ScopeLogger::kDevice;
82a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartstatic string ObjectID(const DeviceInfo* d) { return "(device_info)"; }
83c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
84c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein
85b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart// static
86abc5403270e26fa898181301911a905758f8d758Jason Glasgowconst char DeviceInfo::kModemPseudoDeviceNamePrefix[] = "pseudomodem";
87e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wileyconst char DeviceInfo::kEthernetPseudoDeviceNamePrefix[] = "pseudoethernet";
8883d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewartconst char DeviceInfo::kIgnoredDeviceNamePrefix[] = "veth";
89ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kDeviceInfoRoot[] = "/sys/class/net";
904e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chanconst char DeviceInfo::kDriverCdcEther[] = "cdc_ether";
914eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chanconst char DeviceInfo::kDriverCdcNcm[] = "cdc_ncm";
924e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chanconst char DeviceInfo::kDriverGdmWiMax[] = "gdm_wimax";
9393a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawalconst char DeviceInfo::kDriverVirtioNet[] = "virtio_net";
94ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceUevent[] = "uevent";
959364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewartconst char DeviceInfo::kInterfaceUeventWifiSignature[] = "DEVTYPE=wlan\n";
96ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceDevice[] = "device";
97ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceDriver[] = "device/driver";
98ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceTunFlags[] = "tun_flags";
99ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceType[] = "type";
100a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartconst char* DeviceInfo::kModemDrivers[] = {
101b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    "gobi",
102b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    "QCUSBNet2k",
103226d46a2e03d316e8a36f93cb261f708219aef07Ben Chan    "GobiNet",
1040f90e0b62322ae95c1a419d5efef47438b4617c9Ben Chan    "cdc_mbim",
105226d46a2e03d316e8a36f93cb261f708219aef07Ben Chan    "qmi_wwan"
106b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart};
107cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewartconst char DeviceInfo::kTunDeviceName[] = "/dev/net/tun";
108050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartconst int DeviceInfo::kDelayedDeviceCreationSeconds = 5;
109b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chanconst int DeviceInfo::kRequestLinkStatisticsIntervalMilliseconds = 20000;
110b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
111a794cd60a7339d576ea2eed263a4f0a20fb255afPaul StewartDeviceInfo::DeviceInfo(ControlInterface* control_interface,
112a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                       EventDispatcher* dispatcher,
113a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                       Metrics* metrics,
114a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                       Manager* manager)
115a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart    : control_interface_(control_interface),
116a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart      dispatcher_(dispatcher),
1173426c8fc7a3943f2d8fcb2ec78f0593088b42bedThieu Le      metrics_(metrics),
118a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart      manager_(manager),
1193e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      link_callback_(Bind(&DeviceInfo::LinkMsgHandler, Unretained(this))),
1203e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      address_callback_(Bind(&DeviceInfo::AddressMsgHandler, Unretained(this))),
1219855170e6e2de08db343640c82795c9b4020a166Peter Qiu      rdnss_callback_(Bind(&DeviceInfo::RdnssMsgHandler, Unretained(this))),
122ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      device_info_root_(kDeviceInfoRoot),
1238c116a90d3a3536430b808b15e73275060918434Paul Stewart      routing_table_(RoutingTable::GetInstance()),
1244178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain      rtnl_handler_(RTNLHandler::GetInstance()),
1251a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#if !defined(DISABLE_WIFI)
1262ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      netlink_manager_(NetlinkManager::GetInstance()),
1271a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#endif  // DISABLE_WIFI
1289855170e6e2de08db343640c82795c9b4020a166Peter Qiu      sockets_(new Sockets()),
1299855170e6e2de08db343640c82795c9b4020a166Peter Qiu      time_(Time::GetInstance()) {
1300af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1310af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
132a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul StewartDeviceInfo::~DeviceInfo() {}
1330af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
134a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::AddDeviceToBlackList(const string& device_name) {
1358f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal  black_list_.insert(device_name);
1367e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu  // Remove the current device info if it exist, since it will be out-dated.
1377e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu  RemoveInfo(GetIndex(device_name));
1387e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu  // Request link info update to allow device info to be recreated.
139ebd709e7d7519915930404be7120cd8070b432c4Peter Qiu  if (manager_->running()) {
140ebd709e7d7519915930404be7120cd8070b432c4Peter Qiu    rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
141ebd709e7d7519915930404be7120cd8070b432c4Peter Qiu  }
1427e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu}
1437e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu
144a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::RemoveDeviceFromBlackList(const string& device_name) {
1457e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu  black_list_.erase(device_name);
1467e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu  // Remove the current device info if it exist, since it will be out-dated.
1477e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu  RemoveInfo(GetIndex(device_name));
1487e8b8ee34816575b9059dd041ef29f91fe1d15c8Peter Qiu  // Request link info update to allow device info to be recreated.
149ebd709e7d7519915930404be7120cd8070b432c4Peter Qiu  if (manager_->running()) {
150ebd709e7d7519915930404be7120cd8070b432c4Peter Qiu    rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
151ebd709e7d7519915930404be7120cd8070b432c4Peter Qiu  }
1528f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal}
1538f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal
154a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::IsDeviceBlackListed(const string& device_name) {
1555e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood  return ContainsKey(black_list_, device_name);
1565e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood}
1575e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood
158a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewartvoid DeviceInfo::Start() {
159a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart  link_listener_.reset(
1603e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestLink, link_callback_));
1619a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  address_listener_.reset(
1623e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestAddr, address_callback_));
1639855170e6e2de08db343640c82795c9b4020a166Peter Qiu  rdnss_listener_.reset(
1649855170e6e2de08db343640c82795c9b4020a166Peter Qiu      new RTNLListener(RTNLHandler::kRequestRdnss, rdnss_callback_));
1659a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink |
1669a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                             RTNLHandler::kRequestAddr);
1671ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  request_link_statistics_callback_.Reset(
1681ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart      Bind(&DeviceInfo::RequestLinkStatistics, AsWeakPtr()));
1691ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  dispatcher_->PostDelayedTask(request_link_statistics_callback_.callback(),
170b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan                               kRequestLinkStatisticsIntervalMilliseconds);
1710af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1720af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
173a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewartvoid DeviceInfo::Stop() {
1749a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  link_listener_.reset();
1759a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  address_listener_.reset();
1768c116a90d3a3536430b808b15e73275060918434Paul Stewart  infos_.clear();
1771ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  request_link_statistics_callback_.Cancel();
178050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_callback_.Cancel();
179050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.clear();
1800af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1810af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
1825086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chanvector<string> DeviceInfo::GetUninitializedTechnologies() const {
1835086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  set<string> unique_technologies;
184b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray  set<Technology::Identifier> initialized_technologies;
185a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  for (const auto& info : infos_) {
1866db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    Technology::Identifier technology = info.second.technology;
1876db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    if (info.second.device) {
188b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      // If there is more than one device for a technology and at least
189b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      // one of them has been initialized, make sure that it doesn't get
190b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      // listed as uninitialized.
191b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      initialized_technologies.insert(technology);
192b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      unique_technologies.erase(Technology::NameFromIdentifier(technology));
193b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      continue;
194b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray    }
195b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray    if (Technology::IsPrimaryConnectivityTechnology(technology) &&
196b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray        !ContainsKey(initialized_technologies, technology))
1975086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan      unique_technologies.insert(Technology::NameFromIdentifier(technology));
1985086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  }
1995086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  return vector<string>(unique_technologies.begin(), unique_technologies.end());
2005086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan}
2015086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan
202a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::RegisterDevice(const DeviceRefPtr& device) {
203c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(" << device->link_name() << ", "
204c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << device->interface_index() << ")";
2058ce932a8ebf3af11f17b814c4e544a305607afcaChristopher Grant  device->Initialize();
206050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.erase(device->interface_index());
207e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  CHECK(!GetDevice(device->interface_index()).get());
208e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  infos_[device->interface_index()].device = device;
2099abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le  if (metrics_->IsDeviceRegistered(device->interface_index(),
2109abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le                                   device->technology())) {
2119abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le    metrics_->NotifyDeviceInitialized(device->interface_index());
2129abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le  } else {
2139abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le    metrics_->RegisterDevice(device->interface_index(), device->technology());
2149abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le  }
2155086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  if (Technology::IsPrimaryConnectivityTechnology(device->technology())) {
2166f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov    manager_->RegisterDevice(device);
2176f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov  }
2186f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov}
2196f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov
220a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::DeregisterDevice(const DeviceRefPtr& device) {
221e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  int interface_index = device->interface_index();
222e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
223c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(" << device->link_name() << ", "
224c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << interface_index << ")";
225da798623389b981130cd1922f880736f1e0e36baJoshua Kroll  CHECK((device->technology() == Technology::kCellular) ||
226da798623389b981130cd1922f880736f1e0e36baJoshua Kroll        (device->technology() == Technology::kWiMax));
227e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
228e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  // Release reference to the device
229e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  map<int, Info>::iterator iter = infos_.find(interface_index);
230e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  if (iter != infos_.end()) {
231c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Removing device from info for index: "
232c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << interface_index;
233e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    manager_->DeregisterDevice(device);
234e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    // Release the reference to the device, but maintain the mapping
235e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    // for the index.  That will be cleaned up by an RTNL message.
236cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan    iter->second.device = nullptr;
237e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  }
238c8078a6c44d0e30b71642856ef46e0cf6c5edb46Thieu Le  metrics_->DeregisterDevice(device->interface_index());
239e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow}
240e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
241a794cd60a7339d576ea2eed263a4f0a20fb255afPaul StewartFilePath DeviceInfo::GetDeviceInfoPath(const string& iface_name,
242a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                       const string& path_name) {
243ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  return device_info_root_.Append(iface_name).Append(path_name);
244ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
245ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
246a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::GetDeviceInfoContents(const string& iface_name,
247a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                       const string& path_name,
248a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                       string* contents_out) {
249a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  return base::ReadFileToString(GetDeviceInfoPath(iface_name, path_name),
250a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan                                contents_out);
251ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
252a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart
253a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::GetDeviceInfoSymbolicLink(const string& iface_name,
254a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                           const string& path_name,
255a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                           FilePath* path_out) {
256a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  return base::ReadSymbolicLink(GetDeviceInfoPath(iface_name, path_name),
257a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan                                path_out);
258ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
259ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
260fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul StewartTechnology::Identifier DeviceInfo::GetDeviceTechnology(
261a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& iface_name) {
262ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  string type_string;
2632ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  int arp_type = ARPHRD_VOID;
264ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (GetDeviceInfoContents(iface_name, kInterfaceType, &type_string) &&
265a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan      base::TrimString(type_string, "\n", &type_string) &&
266ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      !base::StringToInt(type_string, &arp_type)) {
267ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    arp_type = ARPHRD_VOID;
268ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  }
269ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
2709364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  string contents;
271ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (!GetDeviceInfoContents(iface_name, kInterfaceUevent, &contents)) {
272050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    LOG(INFO) << StringPrintf("%s: device %s has no uevent file",
273050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                              __func__, iface_name.c_str());
274fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    return Technology::kUnknown;
2759364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
276b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2778f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // If the "uevent" file contains the string "DEVTYPE=wlan\n" at the
2788f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // start of the file or after a newline, we can safely assume this
2798f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // is a wifi device.
2809364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  if (contents.find(kInterfaceUeventWifiSignature) != string::npos) {
281c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2)
282fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan        << StringPrintf("%s: device %s has wifi signature in uevent file",
283fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                        __func__, iface_name.c_str());
284ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_IEEE80211_RADIOTAP) {
285c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << StringPrintf("%s: wifi device %s is in monitor mode",
286c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                    __func__, iface_name.c_str());
2872001a42edf1d42ec828a9baf3157496c20fefd49Paul Stewart      return Technology::kWiFiMonitor;
2882001a42edf1d42ec828a9baf3157496c20fefd49Paul Stewart    }
289fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    return Technology::kWifi;
2909364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
291b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2927904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  // Special case for pseudo modems which are used for testing
2937904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  if (iface_name.find(kModemPseudoDeviceNamePrefix) == 0) {
294c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << StringPrintf(
2957904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow        "%s: device %s is a pseudo modem for testing",
2967904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow        __func__, iface_name.c_str());
2977904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow    return Technology::kCellular;
2987904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  }
2997904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow
300e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley  // Special case for pseudo ethernet devices which are used for testing.
301e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley  if (iface_name.find(kEthernetPseudoDeviceNamePrefix) == 0) {
302c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << StringPrintf(
303e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley        "%s: device %s is a virtual ethernet device for testing",
304e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley        __func__, iface_name.c_str());
305e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley    return Technology::kEthernet;
306e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley  }
307e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley
30883d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart  // Special case for devices which should be ignored.
30983d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart  if (iface_name.find(kIgnoredDeviceNamePrefix) == 0) {
31083d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart    SLOG(this, 2) << StringPrintf(
31183d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart        "%s: device %s should be ignored", __func__, iface_name.c_str());
31283d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart    return Technology::kUnknown;
31383d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart  }
31483d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart
3159364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  FilePath driver_path;
316ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (!GetDeviceInfoSymbolicLink(iface_name, kInterfaceDriver, &driver_path)) {
317c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << StringPrintf("%s: device %s has no device symlink",
318c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                  __func__, iface_name.c_str());
319ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_LOOPBACK) {
320c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << StringPrintf("%s: device %s is a loopback device",
321c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                    __func__, iface_name.c_str());
322e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart      return Technology::kLoopback;
323e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart    }
324ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_PPP) {
325c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << StringPrintf("%s: device %s is a ppp device",
326c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                    __func__, iface_name.c_str());
327ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      return Technology::kPPP;
328ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    }
329ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    string tun_flags_str;
330cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    int tun_flags = 0;
331ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (GetDeviceInfoContents(iface_name, kInterfaceTunFlags, &tun_flags_str) &&
332a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan        base::TrimString(tun_flags_str, "\n", &tun_flags_str) &&
333ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart        base::HexStringToInt(tun_flags_str, &tun_flags) &&
334cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart        (tun_flags & IFF_TUN)) {
335c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << StringPrintf("%s: device %s is tun device",
336c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                    __func__, iface_name.c_str());
337cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      return Technology::kTunnel;
338cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    }
339da8cbeef4735df05dd3a9a069c6ecccf37803e60Paul Stewart
34083d625655edbc7c35fc436b8b8fe744886d0aae1Paul Stewart    // We don't know what sort of device it is.
341a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart    return Technology::kNoDeviceSymlink;
3429364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
343b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
3449364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  string driver_name(driver_path.BaseName().value());
3458f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // See if driver for this interface is in a list of known modem driver names.
3468f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  for (size_t modem_idx = 0; modem_idx < arraysize(kModemDrivers);
3478f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le       ++modem_idx) {
3489364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart    if (driver_name == kModemDrivers[modem_idx]) {
349c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2)
350fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan          << StringPrintf("%s: device %s is matched with modem driver %s",
351fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                          __func__, iface_name.c_str(), driver_name.c_str());
3529364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart      return Technology::kCellular;
3539364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart    }
354b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
3550af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
3564e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan  if (driver_name == kDriverGdmWiMax) {
357c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << StringPrintf("%s: device %s is a WiMAX device",
358c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                  __func__, iface_name.c_str());
3594e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    return Technology::kWiMax;
3604e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan  }
3614e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan
3624eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // For cdc_ether / cdc_ncm devices, make sure it's a modem because this driver
3638f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // can be used for other ethernet devices.
3644eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  if (driver_name == kDriverCdcEther || driver_name == kDriverCdcNcm) {
3654eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan    if (IsCdcEthernetModemDevice(iface_name)) {
3664eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan      LOG(INFO) << StringPrintf("%s: device %s is a %s modem device", __func__,
36735ec8408d8b40d74693edc32495b392a525dc238mukesh agrawal                                iface_name.c_str(), driver_name.c_str());
368050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      return Technology::kCellular;
369050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
370c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << StringPrintf("%s: device %s is a %s device", __func__,
371c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                  iface_name.c_str(), driver_name.c_str());
372050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    return Technology::kCDCEthernet;
3738f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
374abc5403270e26fa898181301911a905758f8d758Jason Glasgow
37593a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  // Special case for the virtio driver, used when run under KVM. See also
37693a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  // the comment in VirtioEthernet::Start.
37793a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  if (driver_name == kDriverVirtioNet) {
378c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << StringPrintf("%s: device %s is virtio ethernet",
379c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                  __func__, iface_name.c_str());
38093a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal    return Technology::kVirtioEthernet;
38193a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  }
38293a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal
383c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << StringPrintf("%s: device %s, with driver %s, "
384c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                "is defaulted to type ethernet",
385c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                __func__, iface_name.c_str(),
386c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                driver_name.c_str());
387fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart  return Technology::kEthernet;
388b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart}
389b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
390a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::IsCdcEthernetModemDevice(const std::string& iface_name) {
3914eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // A cdc_ether / cdc_ncm device is a modem device if it also exposes tty
3924eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // interfaces. To determine this, we look for the existence of the tty
3934eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // interface in the USB device sysfs tree.
3948f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
3954eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // A typical sysfs dir hierarchy for a cdc_ether / cdc_ncm modem USB device is
3964eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // as follows:
3978f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
3988f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //   /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2
3998f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.0
4008f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       tty
4018f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         ttyACM0
4028f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.1
4038f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       net
4048f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         usb0
4058f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.2
4068f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       tty
4078f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         ttyACM1
4088f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       ...
4098f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
4108f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // /sys/class/net/usb0/device symlinks to
4118f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2/1-2:1.1
412b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  //
413b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // Note that some modem devices have the tty directory one level deeper
414b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // (eg. E362), so the device tree for the tty interface is:
415b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb/1-2/1-2:1.0/ttyUSB0/tty/ttyUSB0
4168f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
417ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  FilePath device_file = GetDeviceInfoPath(iface_name, kInterfaceDevice);
4188f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  FilePath device_path;
419a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  if (!base::ReadSymbolicLink(device_file, &device_path)) {
420c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << StringPrintf("%s: device %s has no device symlink",
421c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                                  __func__, iface_name.c_str());
4228f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le    return false;
4238f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
4248f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  if (!device_path.IsAbsolute()) {
425a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan    device_path =
426a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan        base::MakeAbsoluteFilePath(device_file.DirName().Append(device_path));
4278f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
4288f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
4298f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // Look for tty interface by enumerating all directories under the parent
430b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // USB device and see if there's a subdirectory "tty" inside.  In other
431b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // words, using the example dir hierarchy above, find
432b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2/.../tty.
4338f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // If this exists, then this is a modem device.
434b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  return HasSubdir(device_path.DirName(), FilePath("tty"));
4358f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le}
4368f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
4378f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le// static
438a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::HasSubdir(const FilePath& base_dir, const FilePath& subdir) {
439a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  FileEnumerator::FileType type = static_cast<FileEnumerator::FileType>(
440a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan      FileEnumerator::DIRECTORIES | FileEnumerator::SHOW_SYM_LINKS);
441a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  FileEnumerator dir_enum(base_dir, true, type);
4428f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  for (FilePath curr_dir = dir_enum.Next(); !curr_dir.empty();
4438f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le       curr_dir = dir_enum.Next()) {
444b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le    if (curr_dir.BaseName() == subdir)
4458f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le      return true;
4468f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
4478f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  return false;
4488f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le}
4498f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
450a794cd60a7339d576ea2eed263a4f0a20fb255afPaul StewartDeviceRefPtr DeviceInfo::CreateDevice(const string& link_name,
451a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                      const string& address,
4528c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      int interface_index,
4538c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      Technology::Identifier technology) {
4548c116a90d3a3536430b808b15e73275060918434Paul Stewart  DeviceRefPtr device;
455050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.erase(interface_index);
4565086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  infos_[interface_index].technology = technology;
4578c116a90d3a3536430b808b15e73275060918434Paul Stewart
4588c116a90d3a3536430b808b15e73275060918434Paul Stewart  switch (technology) {
4598c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kCellular:
4605742b24ab984464701fef0cc7024af2637357b04Ben Chan#if defined(DISABLE_CELLULAR)
4615742b24ab984464701fef0cc7024af2637357b04Ben Chan      LOG(WARNING) << "Cellular support is not implemented. "
4625742b24ab984464701fef0cc7024af2637357b04Ben Chan                   << "Ignore cellular device " << link_name << " at index "
4635742b24ab984464701fef0cc7024af2637357b04Ben Chan                   << interface_index << ".";
464cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan      return nullptr;
4655742b24ab984464701fef0cc7024af2637357b04Ben Chan#else
4668c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Cellular devices are managed by ModemInfo.
467c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << "Cellular link " << link_name
468c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " at index " << interface_index
469c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " -- notifying ModemInfo.";
470bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
471bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      // The MAC address provided by RTNL is not reliable for Gobi 2K modems.
4724b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // Clear it here, and it will be fetched from the kernel in
4734b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // GetMACAddress().
474bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      infos_[interface_index].mac_address.Clear();
4758c116a90d3a3536430b808b15e73275060918434Paul Stewart      manager_->modem_info()->OnDeviceInfoAvailable(link_name);
4768c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4775742b24ab984464701fef0cc7024af2637357b04Ben Chan#endif  // DISABLE_CELLULAR
4788c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kEthernet:
4798c116a90d3a3536430b808b15e73275060918434Paul Stewart      device = new Ethernet(control_interface_, dispatcher_, metrics_,
4808c116a90d3a3536430b808b15e73275060918434Paul Stewart                            manager_, link_name, address, interface_index);
4818c116a90d3a3536430b808b15e73275060918434Paul Stewart      device->EnableIPv6Privacy();
4828c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4838c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kVirtioEthernet:
4848c116a90d3a3536430b808b15e73275060918434Paul Stewart      device = new VirtioEthernet(control_interface_, dispatcher_, metrics_,
4858c116a90d3a3536430b808b15e73275060918434Paul Stewart                                  manager_, link_name, address,
4868c116a90d3a3536430b808b15e73275060918434Paul Stewart                                  interface_index);
4878c116a90d3a3536430b808b15e73275060918434Paul Stewart      device->EnableIPv6Privacy();
4888c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4898c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kWifi:
4901a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#if defined(DISABLE_WIFI)
4911a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu      LOG(WARNING) << "WiFi support is not implemented. Ignore WiFi link "
4921a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu                   << link_name << " at index " << interface_index << ".";
4931a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu      return nullptr;
4941a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#else
4952ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      // Defer creating this device until we get information about the
4962ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      // type of WiFi interface.
4972ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      GetWiFiInterfaceInfo(interface_index);
4988c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4991a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#endif  // DISABLE_WIFI
5004e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    case Technology::kWiMax:
501520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan#if defined(DISABLE_WIMAX)
502520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan      LOG(WARNING) << "WiMax support is not implemented. Ignore WiMax link "
503520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan                   << link_name << " at index " << interface_index << ".";
504cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan      return nullptr;
505520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan#else
506e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      // WiMax devices are managed by WiMaxProvider.
507c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << "WiMax link " << link_name
508c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " at index " << interface_index
509c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " -- notifying WiMaxProvider.";
5104b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // The MAC address provided by RTNL may not be the final value as the
5114b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // WiMAX device may change the address after initialization. Clear it
5124b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // here, and it will be fetched from the kernel when
5134b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // WiMaxProvider::CreateDevice() is called after the WiMAX device DBus
5144b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // object is created by the WiMAX manager daemon.
5154b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      infos_[interface_index].mac_address.Clear();
516e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      manager_->wimax_provider()->OnDeviceInfoAvailable(link_name);
5174e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan      break;
518520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan#endif  // DISABLE_WIMAX
5198c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kPPP:
5208c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kTunnel:
5218c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Tunnel and PPP devices are managed by the VPN code (PPP for
5228c116a90d3a3536430b808b15e73275060918434Paul Stewart      // l2tpipsec).  Notify the VPN Provider of the interface's presence.
5238c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Since CreateDevice is only called once in the lifetime of an
5248c116a90d3a3536430b808b15e73275060918434Paul Stewart      // interface index, this notification will only occur the first
5258c116a90d3a3536430b808b15e73275060918434Paul Stewart      // time the device is seen.
526c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << "Tunnel / PPP link " << link_name
527c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " at index " << interface_index
528c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " -- notifying VPNProvider.";
5298c116a90d3a3536430b808b15e73275060918434Paul Stewart      if (!manager_->vpn_provider()->OnDeviceInfoAvailable(link_name,
5308c116a90d3a3536430b808b15e73275060918434Paul Stewart                                                           interface_index) &&
5318c116a90d3a3536430b808b15e73275060918434Paul Stewart          technology == Technology::kTunnel) {
5328c116a90d3a3536430b808b15e73275060918434Paul Stewart        // If VPN does not know anything about this tunnel, it is probably
5338c116a90d3a3536430b808b15e73275060918434Paul Stewart        // left over from a previous instance and should not exist.
534c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein        SLOG(this, 2) << "Tunnel link is unused.  Deleting.";
5358c116a90d3a3536430b808b15e73275060918434Paul Stewart        DeleteInterface(interface_index);
5368c116a90d3a3536430b808b15e73275060918434Paul Stewart      }
5378c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
5388c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kLoopback:
5398c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Loopback devices are largely ignored, but we should make sure the
5408c116a90d3a3536430b808b15e73275060918434Paul Stewart      // link is enabled.
541c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << "Bringing up loopback device " << link_name
542c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " at index " << interface_index;
5438c116a90d3a3536430b808b15e73275060918434Paul Stewart      rtnl_handler_->SetInterfaceFlags(interface_index, IFF_UP, IFF_UP);
544cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan      return nullptr;
545050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    case Technology::kCDCEthernet:
5464eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan      // CDCEthernet devices are of indeterminate type when they are
547050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // initially created.  Some time later, tty devices may or may
548050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // not appear under the same USB device root, which will identify
549050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // it as a modem.  Alternatively, ModemManager may discover the
550050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // device and create and register a Cellular device.  In either
551050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // case, we should delay creating a Device until we can make a
552050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // better determination of what type this Device should be.
553a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart    case Technology::kNoDeviceSymlink:  // FALLTHROUGH
554a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      // The same is true for devices that do not report a device
555a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      // symlink.  It has been observed that tunnel devices may not
556a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      // immediately contain a tun_flags component in their
557a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      // /sys/class/net entry.
558050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(INFO) << "Delaying creation of device for " << link_name
559050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                << " at index " << interface_index;
560050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      DelayDeviceCreation(interface_index);
561cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan      return nullptr;
5628c116a90d3a3536430b808b15e73275060918434Paul Stewart    default:
5638c116a90d3a3536430b808b15e73275060918434Paul Stewart      // We will not manage this device in shill.  Do not create a device
5648c116a90d3a3536430b808b15e73275060918434Paul Stewart      // object or do anything to change its state.  We create a stub object
5658c116a90d3a3536430b808b15e73275060918434Paul Stewart      // which is useful for testing.
5668c116a90d3a3536430b808b15e73275060918434Paul Stewart      return new DeviceStub(control_interface_, dispatcher_, metrics_,
5678c116a90d3a3536430b808b15e73275060918434Paul Stewart                            manager_, link_name, address, interface_index,
5684e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                            technology);
5698c116a90d3a3536430b808b15e73275060918434Paul Stewart  }
5708c116a90d3a3536430b808b15e73275060918434Paul Stewart
5718c116a90d3a3536430b808b15e73275060918434Paul Stewart  // Reset the routing table and addresses.
5728c116a90d3a3536430b808b15e73275060918434Paul Stewart  routing_table_->FlushRoutes(interface_index);
5738c116a90d3a3536430b808b15e73275060918434Paul Stewart  FlushAddresses(interface_index);
5748c116a90d3a3536430b808b15e73275060918434Paul Stewart
5755086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  manager_->UpdateUninitializedTechnologies();
5765086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan
5778c116a90d3a3536430b808b15e73275060918434Paul Stewart  return device;
5788c116a90d3a3536430b808b15e73275060918434Paul Stewart}
5798c116a90d3a3536430b808b15e73275060918434Paul Stewart
580d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart// static
581d84f367304e8eec21f235392c57bfc1a30540609Paul Stewartbool DeviceInfo::GetLinkNameFromMessage(const RTNLMessage& msg,
582d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart                                        string* link_name) {
583d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  if (!msg.HasAttribute(IFLA_IFNAME))
584d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    return false;
585d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
586d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  ByteString link_name_bytes(msg.GetAttribute(IFLA_IFNAME));
587d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  link_name->assign(reinterpret_cast<const char*>(
588d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart      link_name_bytes.GetConstData()));
589d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
590d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  return true;
591d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart}
592d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
593d84f367304e8eec21f235392c57bfc1a30540609Paul Stewartbool DeviceInfo::IsRenamedBlacklistedDevice(const RTNLMessage& msg) {
594d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  int interface_index = msg.interface_index();
595d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  const Info* info = GetInfo(interface_index);
596d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  if (!info)
597d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    return false;
598d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
599d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  if (!info->device || info->device->technology() != Technology::kBlacklisted)
600d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    return false;
601d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
602d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  string interface_name;
603d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  if (!GetLinkNameFromMessage(msg, &interface_name))
604d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    return false;
605d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
606d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  if (interface_name == info->name)
607d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    return false;
608d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
609d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  LOG(INFO) << __func__ << ": interface index " << interface_index
610d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart            << " renamed from " << info->name << " to " << interface_name;
611d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  return true;
612d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart}
613d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
614d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
615a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::AddLinkMsgHandler(const RTNLMessage& msg) {
6169a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
6179a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart         msg.mode() == RTNLMessage::kModeAdd);
6182aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone  int dev_index = msg.interface_index();
619fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart  Technology::Identifier technology = Technology::kUnknown;
620e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  unsigned int flags = msg.link_status().flags;
621e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  unsigned int change = msg.link_status().change;
622d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
623d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  if (IsRenamedBlacklistedDevice(msg)) {
624d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    // Treat renamed blacklisted devices as new devices.
625d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    RemoveInfo(dev_index);
626d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart  }
627d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart
6288c116a90d3a3536430b808b15e73275060918434Paul Stewart  bool new_device =
6298c116a90d3a3536430b808b15e73275060918434Paul Stewart      !ContainsKey(infos_, dev_index) || infos_[dev_index].has_addresses_only;
630c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(index=" << dev_index
631c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << std::showbase << std::hex
632c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ", flags=" << flags << ", change=" << change << ")"
633c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << std::dec << std::noshowbase
634c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << ", new_device=" << new_device;
6358c116a90d3a3536430b808b15e73275060918434Paul Stewart  infos_[dev_index].has_addresses_only = false;
636e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  infos_[dev_index].flags = flags;
637f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewart
6381ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  RetrieveLinkStatistics(dev_index, msg);
6391ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
6406f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov  DeviceRefPtr device = GetDevice(dev_index);
6418c116a90d3a3536430b808b15e73275060918434Paul Stewart  if (new_device) {
6428c116a90d3a3536430b808b15e73275060918434Paul Stewart    CHECK(!device);
643d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    string link_name;
644d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart    if (!GetLinkNameFromMessage(msg, &link_name)) {
645d84f367304e8eec21f235392c57bfc1a30540609Paul Stewart      LOG(ERROR) << "Add Link message does not contain a link name!";
6462aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone      return;
647b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    }
648c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "add link index "  << dev_index << " name " << link_name;
649f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    infos_[dev_index].name = link_name;
650f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    indices_[link_name] = dev_index;
651a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart
6522aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    if (!link_name.empty()) {
653c1d447354db29b83262c7db0857baa84e05e0c2aChristopher Grant      if (IsDeviceBlackListed(link_name)) {
654fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart        technology = Technology::kBlacklisted;
655c1d447354db29b83262c7db0857baa84e05e0c2aChristopher Grant      } else if (!manager_->DeviceManagementAllowed(link_name)) {
656c1d447354db29b83262c7db0857baa84e05e0c2aChristopher Grant        technology = Technology::kBlacklisted;
657c1d447354db29b83262c7db0857baa84e05e0c2aChristopher Grant        AddDeviceToBlackList(link_name);
6588f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      } else {
6598f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal        technology = GetDeviceTechnology(link_name);
6608f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      }
661633ac6f0d56a62f8fd21ba7d9a15818fe080fb2fDarin Petkov    }
662cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    string address;
663cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    if (msg.HasAttribute(IFLA_ADDRESS)) {
664cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      infos_[dev_index].mac_address = msg.GetAttribute(IFLA_ADDRESS);
6650353c22fb3bfb443b5eeb7fe08b9e9b5dd2c5e3bBen Chan      address =
6663a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko          base::ToLowerASCII(infos_[dev_index].mac_address.HexEncode());
667c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << "link index " << dev_index << " address "
668c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << infos_[dev_index].mac_address.HexEncode();
669ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    } else if (technology != Technology::kTunnel &&
670a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart               technology != Technology::kPPP &&
671a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart               technology != Technology::kNoDeviceSymlink) {
6726813e7624f1047872eeceec14db45373e30e268emukesh agrawal      LOG(ERROR) << "Add Link message for link '" << link_name
6736813e7624f1047872eeceec14db45373e30e268emukesh agrawal                 << "' does not have IFLA_ADDRESS!";
674cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      return;
675cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    }
676c8078a6c44d0e30b71642856ef46e0cf6c5edb46Thieu Le    metrics_->RegisterDevice(dev_index, technology);
6778c116a90d3a3536430b808b15e73275060918434Paul Stewart    device = CreateDevice(link_name, address, dev_index, technology);
6788c116a90d3a3536430b808b15e73275060918434Paul Stewart    if (device) {
6798c116a90d3a3536430b808b15e73275060918434Paul Stewart      RegisterDevice(device);
680b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    }
681b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
6828c116a90d3a3536430b808b15e73275060918434Paul Stewart  if (device) {
6838c116a90d3a3536430b808b15e73275060918434Paul Stewart    device->LinkEvent(flags, change);
6848c116a90d3a3536430b808b15e73275060918434Paul Stewart  }
685b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart}
686b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
687a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::DelLinkMsgHandler(const RTNLMessage& msg) {
688c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(index=" << msg.interface_index() << ")";
68947009f8d7a6fbc257a1bb1288a01405d034bd13fmukesh agrawal
6909a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
6919a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart         msg.mode() == RTNLMessage::kModeDelete);
692c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(index=" << msg.interface_index()
693c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << std::showbase << std::hex
694fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", flags=" << msg.link_status().flags
695fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", change=" << msg.link_status().change << ")";
696e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  RemoveInfo(msg.interface_index());
697e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
698e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
699e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin PetkovDeviceRefPtr DeviceInfo::GetDevice(int interface_index) const {
700a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
701cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan  return info ? info->device : nullptr;
70267d8ecfd1d6ff5ea75b9d5c7167d9c16891d3d4bDarin Petkov}
703b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
704a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartint DeviceInfo::GetIndex(const string& interface_name) const {
705f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  map<string, int>::const_iterator it = indices_.find(interface_name);
706f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  return it == indices_.end() ? -1 : it->second;
707f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov}
708f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov
709a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::GetMACAddress(int interface_index, ByteString* address) const {
710a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
711e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  if (!info) {
712e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov    return false;
713e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  }
714bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // |mac_address| from RTNL is not used for some devices, in which case it will
715bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // be empty here.
716bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (!info->mac_address.IsEmpty()) {
717bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    *address = info->mac_address;
718bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    return true;
719bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
720bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
721bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // Ask the kernel for the MAC address.
722bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  *address = GetMACAddressFromKernel(interface_index);
723bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  return !address->IsEmpty();
724bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain}
725bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
726bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary MorainByteString DeviceInfo::GetMACAddressFromKernel(int interface_index) const {
727a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
7284178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  if (!info) {
7294178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain    return ByteString();
7304178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  }
7314178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain
7324178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  const int fd = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
733bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (fd < 0) {
734fc93327b9bb58605b3fce1d67d6980d1a4752b7eNingyuan Wang    PLOG(ERROR) << __func__ << ": Unable to open socket";
7354178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain    return ByteString();
736bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
7374178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain
7384178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  ScopedSocketCloser socket_closer(sockets_.get(), fd);
739bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  struct ifreq ifr;
740bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  memset(&ifr, 0, sizeof(ifr));
741bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  ifr.ifr_ifindex = interface_index;
7428a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko  strcpy(ifr.ifr_ifrn.ifrn_name, info->name.c_str());  // NOLINT(runtime/printf)
7434178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  int err = sockets_->Ioctl(fd, SIOCGIFHWADDR, &ifr);
744bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (err < 0) {
745fc93327b9bb58605b3fce1d67d6980d1a4752b7eNingyuan Wang    PLOG(ERROR) << __func__ << ": Unable to read MAC address";
7464178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain    return ByteString();
747bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
7484178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain
7494178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  return ByteString(ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
750e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov}
751e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov
7526950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewartbool DeviceInfo::GetMACAddressOfPeer(int interface_index,
753a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                     const IPAddress& peer,
754a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                     ByteString* mac_address) const {
755a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
7566950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (!info || !peer.IsValid()) {
7576950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
7586950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
7596950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
7606950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (peer.family() != IPAddress::kFamilyIPv4) {
7616950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    NOTIMPLEMENTED() << ": only implemented for IPv4";
7626950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
7636950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
7646950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
7656950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  const int fd = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
7666950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (fd < 0) {
767fc93327b9bb58605b3fce1d67d6980d1a4752b7eNingyuan Wang    PLOG(ERROR) << __func__ << ": Unable to open socket";
7686950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
7696950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
7706950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
7716950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  ScopedSocketCloser socket_closer(sockets_.get(), fd);
7726950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  struct arpreq areq;
7736950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  memset(&areq, 0, sizeof(areq));
7746950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
7756950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  strncpy(areq.arp_dev, info->name.c_str(), sizeof(areq.arp_dev) - 1);
7766950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  areq.arp_dev[sizeof(areq.arp_dev) - 1] = '\0';
7776950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
778a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  struct sockaddr_in* protocol_address =
779a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart      reinterpret_cast<struct sockaddr_in*>(&areq.arp_pa);
7806950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  protocol_address->sin_family = AF_INET;
7816950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  CHECK_EQ(sizeof(protocol_address->sin_addr.s_addr), peer.GetLength());
7826950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  memcpy(&protocol_address->sin_addr.s_addr, peer.address().GetConstData(),
7836950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart         sizeof(protocol_address->sin_addr.s_addr));
7846950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
785a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  struct sockaddr_in* hardware_address =
786a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart      reinterpret_cast<struct sockaddr_in*>(&areq.arp_ha);
7876950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  hardware_address->sin_family = ARPHRD_ETHER;
7886950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
7896950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  int err = sockets_->Ioctl(fd, SIOCGARP, &areq);
7906950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (err < 0) {
791fc93327b9bb58605b3fce1d67d6980d1a4752b7eNingyuan Wang    PLOG(ERROR) << __func__ << ": Unable to perform ARP lookup";
7926950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
7936950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
7946950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
7956950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  ByteString peer_address(areq.arp_ha.sa_data, IFHWADDRLEN);
7966950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
7976950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (peer_address.IsZero()) {
7986950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    LOG(INFO) << __func__ << ": ARP lookup is still in progress";
7996950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
8006950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
8016950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
8026950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  CHECK(mac_address);
8036950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  *mac_address = peer_address;
8046950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  return true;
8056950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart}
8066950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
8079a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartbool DeviceInfo::GetAddresses(int interface_index,
808a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                              vector<AddressData>* addresses) const {
809a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
8109a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!info) {
8119a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    return false;
8129a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
8139a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  *addresses = info->ip_addresses;
8149a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  return true;
8159a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
8169a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
8179a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartvoid DeviceInfo::FlushAddresses(int interface_index) const {
818c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(" << interface_index << ")";
819a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
8209a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!info) {
8219a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    return;
8229a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
823a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  for (const auto& address_info : info->ip_addresses) {
8246db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    if (address_info.address.family() == IPAddress::kFamilyIPv4 ||
8256db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart        (address_info.scope == RT_SCOPE_UNIVERSE &&
8266db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart         (address_info.flags & ~IFA_F_TEMPORARY) == 0)) {
827c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << __func__ << ": removing ip address "
828c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << address_info.address.ToString()
829c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                    << " from interface " << interface_index;
8306db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart      rtnl_handler_->RemoveInterfaceAddress(interface_index,
8316db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart                                            address_info.address);
8329a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
8339a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
8349a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
8359a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
83605a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewartbool DeviceInfo::HasOtherAddress(
837a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    int interface_index, const IPAddress& this_address) const {
838c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 3) << __func__ << "(" << interface_index << ")";
839a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
84005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  if (!info) {
84105a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    return false;
84205a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  }
84305a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  bool has_other_address = false;
84405a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  bool has_this_address = false;
845a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  for (const auto& local_address : info->ip_addresses) {
846a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    if (local_address.address.family() != this_address.family()) {
84705a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      continue;
84805a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    }
849a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    if (local_address.address.address().Equals(this_address.address())) {
85005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_this_address = true;
85105a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    } else if (this_address.family() == IPAddress::kFamilyIPv4) {
85205a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_other_address = true;
853a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    } else if ((local_address.scope == RT_SCOPE_UNIVERSE &&
854a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart                (local_address.flags & IFA_F_TEMPORARY) == 0)) {
85505a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_other_address = true;
85605a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    }
85705a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  }
85805a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  return has_other_address && !has_this_address;
85905a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart}
86005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart
861d55f6ae45047f984457508d78c70abcd837307eaPaul Stewartbool DeviceInfo::GetPrimaryIPv6Address(int interface_index,
862a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                       IPAddress* address) {
863a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
864d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  if (!info) {
865d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    return false;
866d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  }
867d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  bool has_temporary_address = false;
868241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart  bool has_current_address = false;
869d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  bool has_address = false;
870a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  for (const auto& local_address : info->ip_addresses) {
871d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    if (local_address.address.family() != IPAddress::kFamilyIPv6 ||
872d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart        local_address.scope != RT_SCOPE_UNIVERSE) {
873d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart      continue;
874d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    }
875d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
876241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart    // Prefer non-deprecated addresses to deprecated addresses to match the
877241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart    // kernel's preference.
878241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart    bool is_current_address =
879241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart        ((local_address.flags & IFA_F_DEPRECATED) == 0);
880241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart    if (has_current_address && !is_current_address) {
881241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart      continue;
882241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart    }
883241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart
884d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    // Prefer temporary addresses to non-temporary addresses to match the
885d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    // kernel's preference.
886d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    bool is_temporary_address = ((local_address.flags & IFA_F_TEMPORARY) != 0);
887d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    if (has_temporary_address && !is_temporary_address) {
888d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart      continue;
889d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    }
890d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
891d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    *address = local_address.address;
892d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    has_temporary_address = is_temporary_address;
893241e3f317fe3089dd7dcb4e7c5a34430926d4e2ePaul Stewart    has_current_address = is_current_address;
894d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    has_address = true;
895d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  }
896d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
897d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  return has_address;
898d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart}
899d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
9009855170e6e2de08db343640c82795c9b4020a166Peter Qiubool DeviceInfo::GetIPv6DnsServerAddresses(int interface_index,
901a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                           std::vector<IPAddress>* address_list,
902a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                           uint32_t* life_time) {
903a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
9049855170e6e2de08db343640c82795c9b4020a166Peter Qiu  if (!info || info->ipv6_dns_server_addresses.empty()) {
9059855170e6e2de08db343640c82795c9b4020a166Peter Qiu    return false;
9069855170e6e2de08db343640c82795c9b4020a166Peter Qiu  }
9079855170e6e2de08db343640c82795c9b4020a166Peter Qiu
9089855170e6e2de08db343640c82795c9b4020a166Peter Qiu  // Determine the remaining DNS server life time.
9099855170e6e2de08db343640c82795c9b4020a166Peter Qiu  if (info->ipv6_dns_server_lifetime_seconds == ND_OPT_LIFETIME_INFINITY) {
9109855170e6e2de08db343640c82795c9b4020a166Peter Qiu    *life_time = ND_OPT_LIFETIME_INFINITY;
9119855170e6e2de08db343640c82795c9b4020a166Peter Qiu  } else {
9129855170e6e2de08db343640c82795c9b4020a166Peter Qiu    time_t cur_time;
9139855170e6e2de08db343640c82795c9b4020a166Peter Qiu    if (!time_->GetSecondsBoottime(&cur_time)) {
9149855170e6e2de08db343640c82795c9b4020a166Peter Qiu      NOTREACHED();
9159855170e6e2de08db343640c82795c9b4020a166Peter Qiu    }
9167fab89734d88724a288e96a9996b15548c5294c7Ben Chan    uint32_t time_elapsed = static_cast<uint32_t>(
9179855170e6e2de08db343640c82795c9b4020a166Peter Qiu        cur_time - info->ipv6_dns_server_received_time_seconds);
9189855170e6e2de08db343640c82795c9b4020a166Peter Qiu    if (time_elapsed >= info->ipv6_dns_server_lifetime_seconds) {
9199855170e6e2de08db343640c82795c9b4020a166Peter Qiu      *life_time = 0;
9209855170e6e2de08db343640c82795c9b4020a166Peter Qiu    } else {
9219855170e6e2de08db343640c82795c9b4020a166Peter Qiu      *life_time = info->ipv6_dns_server_lifetime_seconds - time_elapsed;
9229855170e6e2de08db343640c82795c9b4020a166Peter Qiu    }
9239855170e6e2de08db343640c82795c9b4020a166Peter Qiu  }
9249855170e6e2de08db343640c82795c9b4020a166Peter Qiu  *address_list = info->ipv6_dns_server_addresses;
9259855170e6e2de08db343640c82795c9b4020a166Peter Qiu  return true;
9269855170e6e2de08db343640c82795c9b4020a166Peter Qiu}
9279855170e6e2de08db343640c82795c9b4020a166Peter Qiu
928a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewartbool DeviceInfo::HasDirectConnectivityTo(
929a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    int interface_index, const IPAddress& address) const {
930c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 3) << __func__ << "(" << interface_index << ")";
931a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
932a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  if (!info) {
933a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    return false;
934a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  }
935a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart
936a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  for (const auto& local_address : info->ip_addresses) {
937a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    if (local_address.address.family() == address.family() &&
938a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart        local_address.address.CanReachAddress(address)) {
939a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart      return true;
940a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    }
941a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  }
942a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart
943a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  return false;
944a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart}
945a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart
946a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::GetFlags(int interface_index, unsigned int* flags) const {
947a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
948e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (!info) {
949e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    return false;
950e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  }
951e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  *flags = info->flags;
952e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return true;
953e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
954e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
9551ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartbool DeviceInfo::GetByteCounts(int interface_index,
956a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                               uint64_t* rx_bytes,
957a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                               uint64_t* tx_bytes) const {
958a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
9591ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (!info) {
9601ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return false;
9611ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
9621ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  *rx_bytes = info->rx_bytes;
9631ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  *tx_bytes = info->tx_bytes;
9641ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  return true;
9651ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
9661ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
967a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::CreateTunnelInterface(string* interface_name) const {
968cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  int fd = HANDLE_EINTR(open(kTunDeviceName, O_RDWR));
969cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (fd < 0) {
970cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to open " << kTunDeviceName;
971cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
972cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
9736fbf64f493a9aae7d743888039c61a57386203dbBen Chan  base::ScopedFD scoped_fd(fd);
974cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
975cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  struct ifreq ifr;
976cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  memset(&ifr, 0, sizeof(ifr));
977cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
978cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (HANDLE_EINTR(ioctl(fd, TUNSETIFF, &ifr))) {
979cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to create tunnel interface";
980cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
981cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
982cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
983cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (HANDLE_EINTR(ioctl(fd, TUNSETPERSIST, 1))) {
984cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to set tunnel interface to be persistent";
985cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
986cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
987cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
988cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  *interface_name = string(ifr.ifr_name);
989cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
990cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  return true;
991cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart}
992cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
993a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartint DeviceInfo::OpenTunnelInterface(const std::string& interface_name) const {
994127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  int fd = HANDLE_EINTR(open(kTunDeviceName, O_RDWR));
995127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  if (fd < 0) {
996127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi    PLOG(ERROR) << "failed to open " << kTunDeviceName;
997127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi    return -1;
998127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  }
999127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi
1000127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  struct ifreq ifr;
1001127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  memset(&ifr, 0, sizeof(ifr));
1002127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  strncpy(ifr.ifr_name, interface_name.c_str(), sizeof(ifr.ifr_name));
1003127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
1004127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  if (HANDLE_EINTR(ioctl(fd, TUNSETIFF, &ifr))) {
1005127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi    PLOG(ERROR) << "failed to set tunnel interface name";
1006127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi    return -1;
1007127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  }
1008127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi
1009127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi  return fd;
1010127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi}
1011127b341755731bd6ecc19e44b63c23c79e0b7cd1Prabhu Kaliamoorthi
1012ca6abd4635507fa5b8f4b8819a37819fb560c464Paul Stewartbool DeviceInfo::DeleteInterface(int interface_index) const {
1013cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  return rtnl_handler_->RemoveInterface(interface_index);
1014cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart}
1015cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
1016a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartconst DeviceInfo::Info* DeviceInfo::GetInfo(int interface_index) const {
1017e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  map<int, Info>::const_iterator iter = infos_.find(interface_index);
1018e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (iter == infos_.end()) {
1019cc225ef3b77b5e098cc12c661a947e1737480777Ben Chan    return nullptr;
1020e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  }
1021e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return &iter->second;
1022e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
1023e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
1024e6193c042652831cac90c3bbf2233877754b1eefDarin Petkovvoid DeviceInfo::RemoveInfo(int interface_index) {
1025e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  map<int, Info>::iterator iter = infos_.find(interface_index);
1026e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (iter != infos_.end()) {
1027c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Removing info for device index: " << interface_index;
10289f5159e07028a01e1353d68bc19da9817a6785fePeter Qiu    // Deregister the device if not deregistered yet. Cellular and WiMax devices
10299f5159e07028a01e1353d68bc19da9817a6785fePeter Qiu    // are deregistered through a call to DeviceInfo::DeregisterDevice.
1030e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    if (iter->second.device.get()) {
1031e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov      manager_->DeregisterDevice(iter->second.device);
10329f5159e07028a01e1353d68bc19da9817a6785fePeter Qiu      metrics_->DeregisterDevice(interface_index);
1033e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    }
1034f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    indices_.erase(iter->second.name);
1035e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    infos_.erase(iter);
1036050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    delayed_devices_.erase(interface_index);
103747009f8d7a6fbc257a1bb1288a01405d034bd13fmukesh agrawal  } else {
1038c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << ": Unknown device index: "
1039c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << interface_index;
1040b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
10410af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
10420af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
1043a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::LinkMsgHandler(const RTNLMessage& msg) {
10449a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink);
10459a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (msg.mode() == RTNLMessage::kModeAdd) {
10462aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    AddLinkMsgHandler(msg);
10479a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  } else if (msg.mode() == RTNLMessage::kModeDelete) {
10482aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    DelLinkMsgHandler(msg);
10492aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone  } else {
10502aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    NOTREACHED();
1051b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
10520af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
10530af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
1054a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::AddressMsgHandler(const RTNLMessage& msg) {
1055c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
10569a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeAddress);
10579a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  int interface_index = msg.interface_index();
10589a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!ContainsKey(infos_, interface_index)) {
1059c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Got advance address information for unknown index "
1060c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << interface_index;
10618c116a90d3a3536430b808b15e73275060918434Paul Stewart    infos_[interface_index].has_addresses_only = true;
10629a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
1063a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const RTNLMessage::AddressStatus& status = msg.address_status();
10649a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  IPAddress address(msg.family(),
1065682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan                    msg.HasAttribute(IFA_LOCAL) ?
1066682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan                    msg.GetAttribute(IFA_LOCAL) : msg.GetAttribute(IFA_ADDRESS),
10679a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                    status.prefix_len);
10689a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
1069682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan  SLOG_IF(Device, 2, msg.HasAttribute(IFA_LOCAL))
1070682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan      << "Found local address attribute for interface " << interface_index;
1071682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan
1072a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  vector<AddressData>& address_list = infos_[interface_index].ip_addresses;
10739a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  vector<AddressData>::iterator iter;
10749a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  for (iter = address_list.begin(); iter != address_list.end(); ++iter) {
10759a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (address.Equals(iter->address)) {
10769a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      break;
10779a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
10789a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
10799a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (iter != address_list.end()) {
10809a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (msg.mode() == RTNLMessage::kModeDelete) {
1081c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein      SLOG(this, 2) << "Delete address for interface " << interface_index;
10829a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      address_list.erase(iter);
10839a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else {
10849a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      iter->flags = status.flags;
10859a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      iter->scope = status.scope;
10869a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
10879a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  } else if (msg.mode() == RTNLMessage::kModeAdd) {
10889a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    address_list.push_back(AddressData(address, status.flags, status.scope));
1089c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Add address " << address.ToString()
1090c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << " for interface " << interface_index;
10919a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
1092d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
1093d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  DeviceRefPtr device = GetDevice(interface_index);
1094d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  if (device && address.family() == IPAddress::kFamilyIPv6 &&
1095d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart      status.scope == RT_SCOPE_UNIVERSE) {
1096d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    device->OnIPv6AddressChanged();
1097d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  }
10989a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
10999a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
1100a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::RdnssMsgHandler(const RTNLMessage& msg) {
1101c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
11029855170e6e2de08db343640c82795c9b4020a166Peter Qiu  DCHECK(msg.type() == RTNLMessage::kTypeRdnss);
11039855170e6e2de08db343640c82795c9b4020a166Peter Qiu  int interface_index = msg.interface_index();
11049855170e6e2de08db343640c82795c9b4020a166Peter Qiu  if (!ContainsKey(infos_, interface_index)) {
1105c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << "Got RDNSS option for unknown index "
1106c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                  << interface_index;
11079855170e6e2de08db343640c82795c9b4020a166Peter Qiu  }
11089855170e6e2de08db343640c82795c9b4020a166Peter Qiu
1109a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const RTNLMessage::RdnssOption& rdnss_option = msg.rdnss_option();
11109855170e6e2de08db343640c82795c9b4020a166Peter Qiu  infos_[interface_index].ipv6_dns_server_lifetime_seconds =
11119855170e6e2de08db343640c82795c9b4020a166Peter Qiu      rdnss_option.lifetime;
11129855170e6e2de08db343640c82795c9b4020a166Peter Qiu  infos_[interface_index].ipv6_dns_server_addresses = rdnss_option.addresses;
11139855170e6e2de08db343640c82795c9b4020a166Peter Qiu  if (!time_->GetSecondsBoottime(
11149855170e6e2de08db343640c82795c9b4020a166Peter Qiu          &infos_[interface_index].ipv6_dns_server_received_time_seconds)) {
11159855170e6e2de08db343640c82795c9b4020a166Peter Qiu    NOTREACHED();
11169855170e6e2de08db343640c82795c9b4020a166Peter Qiu  }
11179855170e6e2de08db343640c82795c9b4020a166Peter Qiu
11189855170e6e2de08db343640c82795c9b4020a166Peter Qiu  // Notify device of the IPv6 DNS server addresses update.
11199855170e6e2de08db343640c82795c9b4020a166Peter Qiu  DeviceRefPtr device = GetDevice(interface_index);
11209855170e6e2de08db343640c82795c9b4020a166Peter Qiu  if (device) {
11219855170e6e2de08db343640c82795c9b4020a166Peter Qiu    device->OnIPv6DnsServerAddressesChanged();
11229855170e6e2de08db343640c82795c9b4020a166Peter Qiu  }
11239855170e6e2de08db343640c82795c9b4020a166Peter Qiu}
11249855170e6e2de08db343640c82795c9b4020a166Peter Qiu
1125050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartvoid DeviceInfo::DelayDeviceCreation(int interface_index) {
1126050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.insert(interface_index);
1127050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_callback_.Reset(
1128050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      Bind(&DeviceInfo::DelayedDeviceCreationTask, AsWeakPtr()));
1129050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  dispatcher_->PostDelayedTask(delayed_devices_callback_.callback(),
1130050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                               kDelayedDeviceCreationSeconds * 1000);
1131050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart}
1132050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
1133050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart// Re-evaluate the technology type for each delayed device.
1134050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartvoid DeviceInfo::DelayedDeviceCreationTask() {
1135050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  while (!delayed_devices_.empty()) {
1136050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    set<int>::iterator it = delayed_devices_.begin();
1137050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    int dev_index = *it;
1138050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    delayed_devices_.erase(it);
1139050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
1140050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(ContainsKey(infos_, dev_index));
1141050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(!GetDevice(dev_index));
1142050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
1143a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart    const string& link_name = infos_[dev_index].name;
1144050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    Technology::Identifier technology = GetDeviceTechnology(link_name);
1145050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
1146050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    if (technology == Technology::kCDCEthernet) {
1147050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(INFO) << "In " << __func__ << ": device " << link_name
1148050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                << " is now assumed to be regular Ethernet.";
1149050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      technology = Technology::kEthernet;
1150a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart    } else if (technology == Technology::kNoDeviceSymlink) {
1151a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      if (manager_->ignore_unknown_ethernet()) {
1152a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart        SLOG(this, 2) << StringPrintf("%s: device %s, without driver name "
1153a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart                                      "will be ignored",
1154a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart                                      __func__, link_name.c_str());
1155a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart        technology = Technology::kUnknown;
1156a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      } else {
1157a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart        // Act the same as if there was a driver symlink, but we did not
1158a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart        // recognize the driver name.
1159a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart        SLOG(this, 2) << StringPrintf("%s: device %s, without driver name "
1160a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart                                      "is defaulted to type ethernet",
1161a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart                                      __func__, link_name.c_str());
1162a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart        technology = Technology::kEthernet;
1163a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      }
1164a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart    } else if (technology != Technology::kCellular &&
1165a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart               technology != Technology::kTunnel) {
1166050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(WARNING) << "In " << __func__ << ": device " << link_name
1167050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                   << " is unexpected technology "
1168050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                   << Technology::NameFromIdentifier(technology);
1169050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
1170050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    string address =
11713a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko        base::ToLowerASCII(infos_[dev_index].mac_address.HexEncode());
1172a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart
1173d92c35390c2309645b82f37c6172e4fae606b095Christopher Grant    if (technology != Technology::kTunnel &&
1174d92c35390c2309645b82f37c6172e4fae606b095Christopher Grant        technology != Technology::kUnknown) {
1175a551451a88ec3a4746021c84c646dcf8206b2531Paul Stewart      DCHECK(!address.empty());
1176d92c35390c2309645b82f37c6172e4fae606b095Christopher Grant    }
1177050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
1178050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DeviceRefPtr device = CreateDevice(link_name, address, dev_index,
1179050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                                       technology);
1180050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    if (device) {
1181050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      RegisterDevice(device);
1182050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
1183050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  }
1184050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart}
1185050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
11861ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartvoid DeviceInfo::RetrieveLinkStatistics(int interface_index,
1187a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart                                        const RTNLMessage& msg) {
11881ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (!msg.HasAttribute(IFLA_STATS64)) {
11891ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return;
11901ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
11911ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  ByteString stats_bytes(msg.GetAttribute(IFLA_STATS64));
11921ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  struct rtnl_link_stats64 stats;
11931ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (stats_bytes.GetLength() < sizeof(stats)) {
11941ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    LOG(WARNING) << "Link statistics size is too small: "
11951ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                 << stats_bytes.GetLength() << " < " << sizeof(stats);
11961ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return;
11971ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
11981ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
11991ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  memcpy(&stats, stats_bytes.GetConstData(), sizeof(stats));
1200c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "Link statistics for "
1201c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " interface index " << interface_index << ": "
1202c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << "receive: " << stats.rx_bytes << "; "
1203c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << "transmit: " << stats.tx_bytes << ".";
12041ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  infos_[interface_index].rx_bytes = stats.rx_bytes;
12051ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  infos_[interface_index].tx_bytes = stats.tx_bytes;
12061ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
12071ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
12081ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartvoid DeviceInfo::RequestLinkStatistics() {
12091ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
12101ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  dispatcher_->PostDelayedTask(request_link_statistics_callback_.callback(),
1211b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan                               kRequestLinkStatisticsIntervalMilliseconds);
12121ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
12131ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
12141a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#if !defined(DISABLE_WIFI)
12152ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewartvoid DeviceInfo::GetWiFiInterfaceInfo(int interface_index) {
12162ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  GetInterfaceMessage msg;
12172ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (!msg.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
12182ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart                                              interface_index)) {
12192ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Unable to set interface index attribute for "
12202ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart                  "GetInterface message.  Interface type cannot be "
12212ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart                  "determined!";
12222ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
12232ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
12247347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  netlink_manager_->SendNl80211Message(
12257347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie      &msg,
12267347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie      Bind(&DeviceInfo::OnWiFiInterfaceInfoReceived, AsWeakPtr()),
12275412de0a46893b44f60fee4058c5b0d744b74b4dSamuel Tan      Bind(&NetlinkManager::OnAckDoNothing),
12287347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie      Bind(&NetlinkManager::OnNetlinkMessageError));
12292ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart}
12302ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart
1231a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartvoid DeviceInfo::OnWiFiInterfaceInfoReceived(const Nl80211Message& msg) {
12327347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  if (msg.command() != NL80211_CMD_NEW_INTERFACE) {
12332ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Message is not a new interface response";
12342ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
12352ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
12362ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart
12372ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  uint32_t interface_index;
12387347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFINDEX,
12397347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie                                                    &interface_index)) {
12402ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Message contains no interface index";
12412ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
12422ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
12432ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  uint32_t interface_type;
12447347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFTYPE,
12457347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie                                                    &interface_type)) {
12462ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Message contains no interface type";
12472ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
12482ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
1249a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart  const Info* info = GetInfo(interface_index);
12502ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (!info) {
12512ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Could not find device info for interface index "
12522ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart               << interface_index;
12532ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
12542ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
12552ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (info->device) {
12562ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Device already created for interface index "
12572ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart               << interface_index;
12582ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
12592ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
12602ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (interface_type != NL80211_IFTYPE_STATION) {
12612ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(INFO) << "Ignoring WiFi device "
12622ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << info->name
12632ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << " at interface index "
12642ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << interface_index
12652ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << " since it is not in station mode.";
12662ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
12672ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
12682ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  LOG(INFO) << "Creating WiFi device for station mode interface "
12692ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << info->name
12702ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << " at interface index "
12712ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << interface_index;
12723a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  string address = base::ToLowerASCII(info->mac_address.HexEncode());
12732ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  DeviceRefPtr device =
12742ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      new WiFi(control_interface_, dispatcher_, metrics_, manager_,
12752ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart               info->name, address, interface_index);
12762ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  device->EnableIPv6Privacy();
12772ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  RegisterDevice(device);
12782ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart}
12791a72f5444e077ed21b8e085b17d7f9f1bc44fa5ePeter Qiu#endif  // DISABLE_WIFI
12802ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart
1281a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewartbool DeviceInfo::SetHostname(const std::string& hostname) const {
1282208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  if (sethostname(hostname.c_str(), hostname.length())) {
1283208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart    PLOG(ERROR) << "Failed to set hostname to: " << hostname;
1284208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart    return false;
1285208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  }
1286208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart
1287208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart  return true;
1288208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart}
1289208a97ed32c62bc11b0a20eaf01833482e8c0fbcPaul Stewart
12900af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}  // namespace shill
1291