device_info.cc revision 6db7b24348e69639e19cd6c408388b10d6ee54fe
141c0e0accae6602dbc9fc31f336dabee7af1b170Darin Petkov// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
20af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart// Use of this source code is governed by a BSD-style license that can be
30af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart// found in the LICENSE file.
40af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
5cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include "shill/device_info.h"
60af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
70af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <arpa/inet.h>
8cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <fcntl.h>
9cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <linux/if_tun.h>
100af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <linux/netlink.h>
110af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <linux/rtnetlink.h>
12cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <net/if.h>
13cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <net/if_arp.h>
14cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <netinet/ether.h>
15cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <string.h>
16cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <sys/ioctl.h>
17cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <sys/socket.h>
18cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <time.h>
19cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart#include <unistd.h>
20cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
210af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include <string>
220af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
233e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/bind.h>
24bf1861b28b61d2338116e4416ac8f2a45f7045cePaul Stewart#include <base/file_util.h>
25a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/files/file_enumerator.h>
26487b8bfc46a91e29bb23aaf3c59cfe67033bfc8bChris Masone#include <base/memory/scoped_ptr.h>
273e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/stl_util.h>
28a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_number_conversions.h>
29a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_util.h>
30a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/stringprintf.h>
310af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
320af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart#include "shill/control_interface.h"
339be4a9d1e87d64f850f15061123b2a4334477fa2Chris Masone#include "shill/device.h"
34a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart#include "shill/device_stub.h"
35b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart#include "shill/ethernet.h"
36b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h"
37b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart#include "shill/manager.h"
382ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart#include "shill/netlink_attribute.h"
392ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart#include "shill/netlink_manager.h"
402ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart#include "shill/nl80211_message.h"
418c116a90d3a3536430b808b15e73275060918434Paul Stewart#include "shill/routing_table.h"
42a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart#include "shill/rtnl_handler.h"
43a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart#include "shill/rtnl_listener.h"
442aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone#include "shill/rtnl_message.h"
45487b8bfc46a91e29bb23aaf3c59cfe67033bfc8bChris Masone#include "shill/service.h"
464178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain#include "shill/sockets.h"
4793a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal#include "shill/virtio_ethernet.h"
48c3505a569e3f98ce56e4017300a3ce46bc714e4cDarin Petkov#include "shill/vpn_provider.h"
49b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart#include "shill/wifi.h"
500af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
513e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Bind;
52a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chanusing base::FileEnumerator;
530e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulkusing base::FilePath;
548f1c835d879f82261a08257eb6f9677e6be51fdaThieu Leusing base::StringPrintf;
553e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Unretained;
56e6193c042652831cac90c3bbf2233877754b1eefDarin Petkovusing std::map;
57050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartusing std::set;
580af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewartusing std::string;
599a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartusing std::vector;
600af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
610af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewartnamespace shill {
62b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
63b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart// static
64abc5403270e26fa898181301911a905758f8d758Jason Glasgowconst char DeviceInfo::kModemPseudoDeviceNamePrefix[] = "pseudomodem";
65e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wileyconst char DeviceInfo::kEthernetPseudoDeviceNamePrefix[] = "pseudoethernet";
66ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kDeviceInfoRoot[] = "/sys/class/net";
674e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chanconst char DeviceInfo::kDriverCdcEther[] = "cdc_ether";
684eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chanconst char DeviceInfo::kDriverCdcNcm[] = "cdc_ncm";
694e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chanconst char DeviceInfo::kDriverGdmWiMax[] = "gdm_wimax";
7093a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawalconst char DeviceInfo::kDriverVirtioNet[] = "virtio_net";
71ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceUevent[] = "uevent";
729364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewartconst char DeviceInfo::kInterfaceUeventWifiSignature[] = "DEVTYPE=wlan\n";
73ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceDevice[] = "device";
74ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceDriver[] = "device/driver";
75ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceTunFlags[] = "tun_flags";
76ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceType[] = "type";
77b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewartconst char *DeviceInfo::kModemDrivers[] = {
78b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    "gobi",
79b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    "QCUSBNet2k",
80226d46a2e03d316e8a36f93cb261f708219aef07Ben Chan    "GobiNet",
810f90e0b62322ae95c1a419d5efef47438b4617c9Ben Chan    "cdc_mbim",
82226d46a2e03d316e8a36f93cb261f708219aef07Ben Chan    "qmi_wwan"
83b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart};
84cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewartconst char DeviceInfo::kTunDeviceName[] = "/dev/net/tun";
85050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartconst int DeviceInfo::kDelayedDeviceCreationSeconds = 5;
86b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chanconst int DeviceInfo::kRequestLinkStatisticsIntervalMilliseconds = 20000;
87b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
88b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul StewartDeviceInfo::DeviceInfo(ControlInterface *control_interface,
89b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart                       EventDispatcher *dispatcher,
903426c8fc7a3943f2d8fcb2ec78f0593088b42bedThieu Le                       Metrics *metrics,
91b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart                       Manager *manager)
92a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart    : control_interface_(control_interface),
93a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart      dispatcher_(dispatcher),
943426c8fc7a3943f2d8fcb2ec78f0593088b42bedThieu Le      metrics_(metrics),
95a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart      manager_(manager),
963e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      link_callback_(Bind(&DeviceInfo::LinkMsgHandler, Unretained(this))),
973e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      address_callback_(Bind(&DeviceInfo::AddressMsgHandler, Unretained(this))),
98ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      device_info_root_(kDeviceInfoRoot),
998c116a90d3a3536430b808b15e73275060918434Paul Stewart      routing_table_(RoutingTable::GetInstance()),
1004178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain      rtnl_handler_(RTNLHandler::GetInstance()),
1012ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      netlink_manager_(NetlinkManager::GetInstance()),
1024178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain      sockets_(new Sockets()) {
1030af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1040af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
105a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul StewartDeviceInfo::~DeviceInfo() {}
1060af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
1078f317b600a218afe05f2d73c59204bb98269a950mukesh agrawalvoid DeviceInfo::AddDeviceToBlackList(const string &device_name) {
1088f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal  black_list_.insert(device_name);
1098f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal}
1108f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal
1115e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbroodbool DeviceInfo::IsDeviceBlackListed(const string &device_name) {
1125e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood  return ContainsKey(black_list_, device_name);
1135e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood}
1145e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood
115a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewartvoid DeviceInfo::Start() {
116a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart  link_listener_.reset(
1173e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestLink, link_callback_));
1189a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  address_listener_.reset(
1193e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestAddr, address_callback_));
1209a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink |
1219a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                             RTNLHandler::kRequestAddr);
1221ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  request_link_statistics_callback_.Reset(
1231ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart      Bind(&DeviceInfo::RequestLinkStatistics, AsWeakPtr()));
1241ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  dispatcher_->PostDelayedTask(request_link_statistics_callback_.callback(),
125b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan                               kRequestLinkStatisticsIntervalMilliseconds);
1260af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1270af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
128a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewartvoid DeviceInfo::Stop() {
1299a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  link_listener_.reset();
1309a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  address_listener_.reset();
1318c116a90d3a3536430b808b15e73275060918434Paul Stewart  infos_.clear();
1321ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  request_link_statistics_callback_.Cancel();
133050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_callback_.Cancel();
134050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.clear();
1350af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1360af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
1375086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chanvector<string> DeviceInfo::GetUninitializedTechnologies() const {
1385086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  set<string> unique_technologies;
139b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray  set<Technology::Identifier> initialized_technologies;
1406db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart  for (const auto &info : infos_) {
1416db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    Technology::Identifier technology = info.second.technology;
1426db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    if (info.second.device) {
143b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      // If there is more than one device for a technology and at least
144b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      // one of them has been initialized, make sure that it doesn't get
145b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      // listed as uninitialized.
146b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      initialized_technologies.insert(technology);
147b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      unique_technologies.erase(Technology::NameFromIdentifier(technology));
148b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray      continue;
149b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray    }
150b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray    if (Technology::IsPrimaryConnectivityTechnology(technology) &&
151b00c13d6444ba67154acffec537bdb466099f7b1Arman Uguray        !ContainsKey(initialized_technologies, technology))
1525086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan      unique_technologies.insert(Technology::NameFromIdentifier(technology));
1535086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  }
1545086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  return vector<string>(unique_technologies.begin(), unique_technologies.end());
1555086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan}
1565086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan
1576f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkovvoid DeviceInfo::RegisterDevice(const DeviceRefPtr &device) {
158fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(" << device->link_name() << ", "
159fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << device->interface_index() << ")";
160050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.erase(device->interface_index());
161e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  CHECK(!GetDevice(device->interface_index()).get());
162e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  infos_[device->interface_index()].device = device;
1639abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le  if (metrics_->IsDeviceRegistered(device->interface_index(),
1649abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le                                   device->technology())) {
1659abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le    metrics_->NotifyDeviceInitialized(device->interface_index());
1669abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le  } else {
1679abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le    metrics_->RegisterDevice(device->interface_index(), device->technology());
1689abd6749e69712e9ec4ed4a54fbba243f16ae7f3Thieu Le  }
1695086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  if (Technology::IsPrimaryConnectivityTechnology(device->technology())) {
1706f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov    manager_->RegisterDevice(device);
1716f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov  }
1726f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov}
1736f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov
174e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgowvoid DeviceInfo::DeregisterDevice(const DeviceRefPtr &device) {
175e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  int interface_index = device->interface_index();
176e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
177fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(" << device->link_name() << ", "
178fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << interface_index << ")";
179da798623389b981130cd1922f880736f1e0e36baJoshua Kroll  CHECK((device->technology() == Technology::kCellular) ||
180da798623389b981130cd1922f880736f1e0e36baJoshua Kroll        (device->technology() == Technology::kWiMax));
181e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
182e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  // Release reference to the device
183e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  map<int, Info>::iterator iter = infos_.find(interface_index);
184e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  if (iter != infos_.end()) {
185fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << "Removing device from info for index: "
186fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                    << interface_index;
187e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    manager_->DeregisterDevice(device);
188e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    // Release the reference to the device, but maintain the mapping
189e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    // for the index.  That will be cleaned up by an RTNL message.
190e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    iter->second.device = NULL;
191e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  }
192c8078a6c44d0e30b71642856ef46e0cf6c5edb46Thieu Le  metrics_->DeregisterDevice(device->interface_index());
193e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow}
194e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
195ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul StewartFilePath DeviceInfo::GetDeviceInfoPath(const string &iface_name,
196ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                       const string &path_name) {
197ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  return device_info_root_.Append(iface_name).Append(path_name);
198ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
199ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
200ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartbool DeviceInfo::GetDeviceInfoContents(const string &iface_name,
201ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                       const string &path_name,
202ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                       string *contents_out) {
203a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  return base::ReadFileToString(GetDeviceInfoPath(iface_name, path_name),
204a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan                                contents_out);
205ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
206ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartbool DeviceInfo::GetDeviceInfoSymbolicLink(const string &iface_name,
2074e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                                           const string &path_name,
2084e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                                           FilePath *path_out) {
209a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  return base::ReadSymbolicLink(GetDeviceInfoPath(iface_name, path_name),
210a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan                                path_out);
211ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
212ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
213fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul StewartTechnology::Identifier DeviceInfo::GetDeviceTechnology(
214fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    const string &iface_name) {
215ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  string type_string;
2162ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  int arp_type = ARPHRD_VOID;
217ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (GetDeviceInfoContents(iface_name, kInterfaceType, &type_string) &&
218a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan      base::TrimString(type_string, "\n", &type_string) &&
219ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      !base::StringToInt(type_string, &arp_type)) {
220ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    arp_type = ARPHRD_VOID;
221ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  }
222ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
2239364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  string contents;
224ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (!GetDeviceInfoContents(iface_name, kInterfaceUevent, &contents)) {
225050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    LOG(INFO) << StringPrintf("%s: device %s has no uevent file",
226050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                              __func__, iface_name.c_str());
227fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    return Technology::kUnknown;
2289364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
229b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2308f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // If the "uevent" file contains the string "DEVTYPE=wlan\n" at the
2318f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // start of the file or after a newline, we can safely assume this
2328f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // is a wifi device.
2339364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  if (contents.find(kInterfaceUeventWifiSignature) != string::npos) {
234fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2)
235fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan        << StringPrintf("%s: device %s has wifi signature in uevent file",
236fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                        __func__, iface_name.c_str());
237ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_IEEE80211_RADIOTAP) {
238fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << StringPrintf("%s: wifi device %s is in monitor mode",
239fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                      __func__, iface_name.c_str());
2402001a42edf1d42ec828a9baf3157496c20fefd49Paul Stewart      return Technology::kWiFiMonitor;
2412001a42edf1d42ec828a9baf3157496c20fefd49Paul Stewart    }
242fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    return Technology::kWifi;
2439364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
244b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2457904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  // Special case for pseudo modems which are used for testing
2467904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  if (iface_name.find(kModemPseudoDeviceNamePrefix) == 0) {
2477904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow    SLOG(Device, 2) << StringPrintf(
2487904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow        "%s: device %s is a pseudo modem for testing",
2497904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow        __func__, iface_name.c_str());
2507904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow    return Technology::kCellular;
2517904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  }
2527904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow
253e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley  // Special case for pseudo ethernet devices which are used for testing.
254e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley  if (iface_name.find(kEthernetPseudoDeviceNamePrefix) == 0) {
255e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley    SLOG(Device, 2) << StringPrintf(
256e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley        "%s: device %s is a virtual ethernet device for testing",
257e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley        __func__, iface_name.c_str());
258e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley    return Technology::kEthernet;
259e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley  }
260e049cc5ad0db026c66cf448cecc48330b9e59360Christopher Wiley
2619364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  FilePath driver_path;
262ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (!GetDeviceInfoSymbolicLink(iface_name, kInterfaceDriver, &driver_path)) {
263fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s has no device symlink",
264fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                    __func__, iface_name.c_str());
265ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_LOOPBACK) {
266fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << StringPrintf("%s: device %s is a loopback device",
267fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                      __func__, iface_name.c_str());
268e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart      return Technology::kLoopback;
269e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart    }
270ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_PPP) {
271ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      SLOG(Device, 2) << StringPrintf("%s: device %s is a ppp device",
272ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                      __func__, iface_name.c_str());
273ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      return Technology::kPPP;
274ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    }
275ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    string tun_flags_str;
276cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    int tun_flags = 0;
277ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (GetDeviceInfoContents(iface_name, kInterfaceTunFlags, &tun_flags_str) &&
278a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan        base::TrimString(tun_flags_str, "\n", &tun_flags_str) &&
279ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart        base::HexStringToInt(tun_flags_str, &tun_flags) &&
280cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart        (tun_flags & IFF_TUN)) {
281fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << StringPrintf("%s: device %s is tun device",
282fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                      __func__, iface_name.c_str());
283cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      return Technology::kTunnel;
284cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    }
285e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart    return Technology::kUnknown;
2869364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
287b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2889364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  string driver_name(driver_path.BaseName().value());
2898f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // See if driver for this interface is in a list of known modem driver names.
2908f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  for (size_t modem_idx = 0; modem_idx < arraysize(kModemDrivers);
2918f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le       ++modem_idx) {
2929364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart    if (driver_name == kModemDrivers[modem_idx]) {
293fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2)
294fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan          << StringPrintf("%s: device %s is matched with modem driver %s",
295fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                          __func__, iface_name.c_str(), driver_name.c_str());
2969364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart      return Technology::kCellular;
2979364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart    }
298b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
2990af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
3004e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan  if (driver_name == kDriverGdmWiMax) {
3014e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s is a WiMAX device",
3024e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                                    __func__, iface_name.c_str());
3034e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    return Technology::kWiMax;
3044e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan  }
3054e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan
3064eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // For cdc_ether / cdc_ncm devices, make sure it's a modem because this driver
3078f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // can be used for other ethernet devices.
3084eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  if (driver_name == kDriverCdcEther || driver_name == kDriverCdcNcm) {
3094eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan    if (IsCdcEthernetModemDevice(iface_name)) {
3104eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan      LOG(INFO) << StringPrintf("%s: device %s is a %s modem device", __func__,
31135ec8408d8b40d74693edc32495b392a525dc238mukesh agrawal                                iface_name.c_str(), driver_name.c_str());
312050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      return Technology::kCellular;
313050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
3144eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s is a %s device", __func__,
31535ec8408d8b40d74693edc32495b392a525dc238mukesh agrawal                                    iface_name.c_str(), driver_name.c_str());
316050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    return Technology::kCDCEthernet;
3178f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
318abc5403270e26fa898181301911a905758f8d758Jason Glasgow
31993a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  // Special case for the virtio driver, used when run under KVM. See also
32093a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  // the comment in VirtioEthernet::Start.
32193a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  if (driver_name == kDriverVirtioNet) {
322fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s is virtio ethernet",
323fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                    __func__, iface_name.c_str());
32493a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal    return Technology::kVirtioEthernet;
32593a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  }
32693a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal
327fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << StringPrintf("%s: device %s, with driver %s, "
328fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                  "is defaulted to type ethernet",
329fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                  __func__, iface_name.c_str(),
330fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                  driver_name.c_str());
331fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart  return Technology::kEthernet;
332b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart}
333b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
3344eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chanbool DeviceInfo::IsCdcEthernetModemDevice(const std::string &iface_name) {
3354eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // A cdc_ether / cdc_ncm device is a modem device if it also exposes tty
3364eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // interfaces. To determine this, we look for the existence of the tty
3374eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // interface in the USB device sysfs tree.
3388f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
3394eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // A typical sysfs dir hierarchy for a cdc_ether / cdc_ncm modem USB device is
3404eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan  // as follows:
3418f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
3428f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //   /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2
3438f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.0
3448f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       tty
3458f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         ttyACM0
3468f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.1
3478f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       net
3488f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         usb0
3498f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.2
3508f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       tty
3518f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         ttyACM1
3528f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       ...
3538f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
3548f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // /sys/class/net/usb0/device symlinks to
3558f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2/1-2:1.1
356b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  //
357b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // Note that some modem devices have the tty directory one level deeper
358b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // (eg. E362), so the device tree for the tty interface is:
359b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb/1-2/1-2:1.0/ttyUSB0/tty/ttyUSB0
3608f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
361ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  FilePath device_file = GetDeviceInfoPath(iface_name, kInterfaceDevice);
3628f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  FilePath device_path;
363a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  if (!base::ReadSymbolicLink(device_file, &device_path)) {
364fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s has no device symlink",
365fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                    __func__, iface_name.c_str());
3668f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le    return false;
3678f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
3688f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  if (!device_path.IsAbsolute()) {
369a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan    device_path =
370a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan        base::MakeAbsoluteFilePath(device_file.DirName().Append(device_path));
3718f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
3728f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
3738f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // Look for tty interface by enumerating all directories under the parent
374b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // USB device and see if there's a subdirectory "tty" inside.  In other
375b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // words, using the example dir hierarchy above, find
376b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2/.../tty.
3778f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // If this exists, then this is a modem device.
378b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  return HasSubdir(device_path.DirName(), FilePath("tty"));
3798f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le}
3808f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
3818f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le// static
382b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Lebool DeviceInfo::HasSubdir(const FilePath &base_dir, const FilePath &subdir) {
383a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  FileEnumerator::FileType type = static_cast<FileEnumerator::FileType>(
384a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan      FileEnumerator::DIRECTORIES | FileEnumerator::SHOW_SYM_LINKS);
385a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  FileEnumerator dir_enum(base_dir, true, type);
3868f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  for (FilePath curr_dir = dir_enum.Next(); !curr_dir.empty();
3878f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le       curr_dir = dir_enum.Next()) {
388b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le    if (curr_dir.BaseName() == subdir)
3898f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le      return true;
3908f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
3918f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  return false;
3928f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le}
3938f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
3948c116a90d3a3536430b808b15e73275060918434Paul StewartDeviceRefPtr DeviceInfo::CreateDevice(const string &link_name,
3958c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      const string &address,
3968c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      int interface_index,
3978c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      Technology::Identifier technology) {
3988c116a90d3a3536430b808b15e73275060918434Paul Stewart  DeviceRefPtr device;
399050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.erase(interface_index);
4005086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  infos_[interface_index].technology = technology;
4018c116a90d3a3536430b808b15e73275060918434Paul Stewart
4028c116a90d3a3536430b808b15e73275060918434Paul Stewart  switch (technology) {
4038c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kCellular:
4045742b24ab984464701fef0cc7024af2637357b04Ben Chan#if defined(DISABLE_CELLULAR)
4055742b24ab984464701fef0cc7024af2637357b04Ben Chan      LOG(WARNING) << "Cellular support is not implemented. "
4065742b24ab984464701fef0cc7024af2637357b04Ben Chan                   << "Ignore cellular device " << link_name << " at index "
4075742b24ab984464701fef0cc7024af2637357b04Ben Chan                   << interface_index << ".";
4085742b24ab984464701fef0cc7024af2637357b04Ben Chan      return NULL;
4095742b24ab984464701fef0cc7024af2637357b04Ben Chan#else
4108c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Cellular devices are managed by ModemInfo.
4118c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << "Cellular link " << link_name
4128c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " at index " << interface_index
4138c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " -- notifying ModemInfo.";
414bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
415bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      // The MAC address provided by RTNL is not reliable for Gobi 2K modems.
4164b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // Clear it here, and it will be fetched from the kernel in
4174b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // GetMACAddress().
418bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      infos_[interface_index].mac_address.Clear();
4198c116a90d3a3536430b808b15e73275060918434Paul Stewart      manager_->modem_info()->OnDeviceInfoAvailable(link_name);
4208c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4215742b24ab984464701fef0cc7024af2637357b04Ben Chan#endif  // DISABLE_CELLULAR
4228c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kEthernet:
4238c116a90d3a3536430b808b15e73275060918434Paul Stewart      device = new Ethernet(control_interface_, dispatcher_, metrics_,
4248c116a90d3a3536430b808b15e73275060918434Paul Stewart                            manager_, link_name, address, interface_index);
4258c116a90d3a3536430b808b15e73275060918434Paul Stewart      device->EnableIPv6Privacy();
4268c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4278c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kVirtioEthernet:
4288c116a90d3a3536430b808b15e73275060918434Paul Stewart      device = new VirtioEthernet(control_interface_, dispatcher_, metrics_,
4298c116a90d3a3536430b808b15e73275060918434Paul Stewart                                  manager_, link_name, address,
4308c116a90d3a3536430b808b15e73275060918434Paul Stewart                                  interface_index);
4318c116a90d3a3536430b808b15e73275060918434Paul Stewart      device->EnableIPv6Privacy();
4328c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4338c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kWifi:
4342ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      // Defer creating this device until we get information about the
4352ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      // type of WiFi interface.
4362ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      GetWiFiInterfaceInfo(interface_index);
4378c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4384e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    case Technology::kWiMax:
439520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan#if defined(DISABLE_WIMAX)
440520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan      LOG(WARNING) << "WiMax support is not implemented. Ignore WiMax link "
441520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan                   << link_name << " at index " << interface_index << ".";
442520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan      return NULL;
443520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan#else
444e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      // WiMax devices are managed by WiMaxProvider.
445e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      SLOG(Device, 2) << "WiMax link " << link_name
446e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov                      << " at index " << interface_index
447e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov                      << " -- notifying WiMaxProvider.";
4484b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // The MAC address provided by RTNL may not be the final value as the
4494b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // WiMAX device may change the address after initialization. Clear it
4504b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // here, and it will be fetched from the kernel when
4514b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // WiMaxProvider::CreateDevice() is called after the WiMAX device DBus
4524b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      // object is created by the WiMAX manager daemon.
4534b28586abe9edee0179ea7672ac5ea9d9dc13ac7Ben Chan      infos_[interface_index].mac_address.Clear();
454e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      manager_->wimax_provider()->OnDeviceInfoAvailable(link_name);
4554e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan      break;
456520eb176ecc8548a9eb6a340fb46c06618ee8308Ben Chan#endif  // DISABLE_WIMAX
4578c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kPPP:
4588c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kTunnel:
4598c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Tunnel and PPP devices are managed by the VPN code (PPP for
4608c116a90d3a3536430b808b15e73275060918434Paul Stewart      // l2tpipsec).  Notify the VPN Provider of the interface's presence.
4618c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Since CreateDevice is only called once in the lifetime of an
4628c116a90d3a3536430b808b15e73275060918434Paul Stewart      // interface index, this notification will only occur the first
4638c116a90d3a3536430b808b15e73275060918434Paul Stewart      // time the device is seen.
4648c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << "Tunnel / PPP link " << link_name
4658c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " at index " << interface_index
4668c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " -- notifying VPNProvider.";
4678c116a90d3a3536430b808b15e73275060918434Paul Stewart      if (!manager_->vpn_provider()->OnDeviceInfoAvailable(link_name,
4688c116a90d3a3536430b808b15e73275060918434Paul Stewart                                                           interface_index) &&
4698c116a90d3a3536430b808b15e73275060918434Paul Stewart          technology == Technology::kTunnel) {
4708c116a90d3a3536430b808b15e73275060918434Paul Stewart        // If VPN does not know anything about this tunnel, it is probably
4718c116a90d3a3536430b808b15e73275060918434Paul Stewart        // left over from a previous instance and should not exist.
4728c116a90d3a3536430b808b15e73275060918434Paul Stewart        SLOG(Device, 2) << "Tunnel link is unused.  Deleting.";
4738c116a90d3a3536430b808b15e73275060918434Paul Stewart        DeleteInterface(interface_index);
4748c116a90d3a3536430b808b15e73275060918434Paul Stewart      }
4758c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4768c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kLoopback:
4778c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Loopback devices are largely ignored, but we should make sure the
4788c116a90d3a3536430b808b15e73275060918434Paul Stewart      // link is enabled.
4798c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << "Bringing up loopback device " << link_name
4808c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " at index " << interface_index;
4818c116a90d3a3536430b808b15e73275060918434Paul Stewart      rtnl_handler_->SetInterfaceFlags(interface_index, IFF_UP, IFF_UP);
4828c116a90d3a3536430b808b15e73275060918434Paul Stewart      return NULL;
483050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    case Technology::kCDCEthernet:
4844eb4ddf7f26286e6b4d112f014718336559dfb7aBen Chan      // CDCEthernet devices are of indeterminate type when they are
485050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // initially created.  Some time later, tty devices may or may
486050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // not appear under the same USB device root, which will identify
487050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // it as a modem.  Alternatively, ModemManager may discover the
488050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // device and create and register a Cellular device.  In either
489050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // case, we should delay creating a Device until we can make a
490050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // better determination of what type this Device should be.
491050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(INFO) << "Delaying creation of device for " << link_name
492050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                << " at index " << interface_index;
493050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      DelayDeviceCreation(interface_index);
494050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      return NULL;
4958c116a90d3a3536430b808b15e73275060918434Paul Stewart    default:
4968c116a90d3a3536430b808b15e73275060918434Paul Stewart      // We will not manage this device in shill.  Do not create a device
4978c116a90d3a3536430b808b15e73275060918434Paul Stewart      // object or do anything to change its state.  We create a stub object
4988c116a90d3a3536430b808b15e73275060918434Paul Stewart      // which is useful for testing.
4998c116a90d3a3536430b808b15e73275060918434Paul Stewart      return new DeviceStub(control_interface_, dispatcher_, metrics_,
5008c116a90d3a3536430b808b15e73275060918434Paul Stewart                            manager_, link_name, address, interface_index,
5014e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                            technology);
5028c116a90d3a3536430b808b15e73275060918434Paul Stewart  }
5038c116a90d3a3536430b808b15e73275060918434Paul Stewart
5048c116a90d3a3536430b808b15e73275060918434Paul Stewart  // Reset the routing table and addresses.
5058c116a90d3a3536430b808b15e73275060918434Paul Stewart  routing_table_->FlushRoutes(interface_index);
5068c116a90d3a3536430b808b15e73275060918434Paul Stewart  FlushAddresses(interface_index);
5078c116a90d3a3536430b808b15e73275060918434Paul Stewart
5085086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan  manager_->UpdateUninitializedTechnologies();
5095086b9744e8330e7f3bd8ab91fe20b53dda28a1cBen Chan
5108c116a90d3a3536430b808b15e73275060918434Paul Stewart  return device;
5118c116a90d3a3536430b808b15e73275060918434Paul Stewart}
5128c116a90d3a3536430b808b15e73275060918434Paul Stewart
5132aa9707f114ab8166f45df5726bf05278df2aef6Chris Masonevoid DeviceInfo::AddLinkMsgHandler(const RTNLMessage &msg) {
5149a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
5159a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart         msg.mode() == RTNLMessage::kModeAdd);
5162aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone  int dev_index = msg.interface_index();
517fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart  Technology::Identifier technology = Technology::kUnknown;
518e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  unsigned int flags = msg.link_status().flags;
519e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  unsigned int change = msg.link_status().change;
5208c116a90d3a3536430b808b15e73275060918434Paul Stewart  bool new_device =
5218c116a90d3a3536430b808b15e73275060918434Paul Stewart      !ContainsKey(infos_, dev_index) || infos_[dev_index].has_addresses_only;
522fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(index=" << dev_index
523fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << std::showbase << std::hex
524fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", flags=" << flags << ", change=" << change << ")"
525fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << std::dec << std::noshowbase
526fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", new_device=" << new_device;
5278c116a90d3a3536430b808b15e73275060918434Paul Stewart  infos_[dev_index].has_addresses_only = false;
528e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  infos_[dev_index].flags = flags;
529f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewart
5301ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  RetrieveLinkStatistics(dev_index, msg);
5311ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
5326f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov  DeviceRefPtr device = GetDevice(dev_index);
5338c116a90d3a3536430b808b15e73275060918434Paul Stewart  if (new_device) {
5348c116a90d3a3536430b808b15e73275060918434Paul Stewart    CHECK(!device);
5352aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    if (!msg.HasAttribute(IFLA_IFNAME)) {
5362aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone      LOG(ERROR) << "Add Link message does not have IFLA_IFNAME!";
5372aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone      return;
538b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    }
5392aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    ByteString b(msg.GetAttribute(IFLA_IFNAME));
5402aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    string link_name(reinterpret_cast<const char*>(b.GetConstData()));
541fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << "add link index "  << dev_index << " name " << link_name;
542f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    infos_[dev_index].name = link_name;
543f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    indices_[link_name] = dev_index;
544a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart
5452aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    if (!link_name.empty()) {
5468f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      if (ContainsKey(black_list_, link_name)) {
547fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart        technology = Technology::kBlacklisted;
5488f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      } else {
5498f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal        technology = GetDeviceTechnology(link_name);
5508f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      }
551633ac6f0d56a62f8fd21ba7d9a15818fe080fb2fDarin Petkov    }
552cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    string address;
553cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    if (msg.HasAttribute(IFLA_ADDRESS)) {
554cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      infos_[dev_index].mac_address = msg.GetAttribute(IFLA_ADDRESS);
555cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      address = StringToLowerASCII(infos_[dev_index].mac_address.HexEncode());
556fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << "link index " << dev_index << " address "
557fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                      << infos_[dev_index].mac_address.HexEncode();
558ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    } else if (technology != Technology::kTunnel &&
559ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart               technology != Technology::kPPP) {
5606813e7624f1047872eeceec14db45373e30e268emukesh agrawal      LOG(ERROR) << "Add Link message for link '" << link_name
5616813e7624f1047872eeceec14db45373e30e268emukesh agrawal                 << "' does not have IFLA_ADDRESS!";
562cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      return;
563cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    }
564c8078a6c44d0e30b71642856ef46e0cf6c5edb46Thieu Le    metrics_->RegisterDevice(dev_index, technology);
5658c116a90d3a3536430b808b15e73275060918434Paul Stewart    device = CreateDevice(link_name, address, dev_index, technology);
5668c116a90d3a3536430b808b15e73275060918434Paul Stewart    if (device) {
5678c116a90d3a3536430b808b15e73275060918434Paul Stewart      RegisterDevice(device);
568b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    }
569b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
5708c116a90d3a3536430b808b15e73275060918434Paul Stewart  if (device) {
5718c116a90d3a3536430b808b15e73275060918434Paul Stewart    device->LinkEvent(flags, change);
5728c116a90d3a3536430b808b15e73275060918434Paul Stewart  }
573b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart}
574b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
5752aa9707f114ab8166f45df5726bf05278df2aef6Chris Masonevoid DeviceInfo::DelLinkMsgHandler(const RTNLMessage &msg) {
576fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(index=" << msg.interface_index() << ")";
57747009f8d7a6fbc257a1bb1288a01405d034bd13fmukesh agrawal
5789a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
5799a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart         msg.mode() == RTNLMessage::kModeDelete);
580fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(index=" << msg.interface_index()
581fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << std::showbase << std::hex
582fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", flags=" << msg.link_status().flags
583fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", change=" << msg.link_status().change << ")";
584e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  RemoveInfo(msg.interface_index());
585e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
586e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
587e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin PetkovDeviceRefPtr DeviceInfo::GetDevice(int interface_index) const {
588e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  const Info *info = GetInfo(interface_index);
589e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return info ? info->device : NULL;
59067d8ecfd1d6ff5ea75b9d5c7167d9c16891d3d4bDarin Petkov}
591b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
592f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkovint DeviceInfo::GetIndex(const string &interface_name) const {
593f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  map<string, int>::const_iterator it = indices_.find(interface_name);
594f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  return it == indices_.end() ? -1 : it->second;
595f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov}
596f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov
5973285296e6624fa0b1b10699f2fa6466d4be10742Paul Stewartbool DeviceInfo::GetMACAddress(int interface_index, ByteString *address) const {
598e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  const Info *info = GetInfo(interface_index);
599e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  if (!info) {
600e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov    return false;
601e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  }
602bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // |mac_address| from RTNL is not used for some devices, in which case it will
603bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // be empty here.
604bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (!info->mac_address.IsEmpty()) {
605bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    *address = info->mac_address;
606bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    return true;
607bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
608bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
609bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // Ask the kernel for the MAC address.
610bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  *address = GetMACAddressFromKernel(interface_index);
611bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  return !address->IsEmpty();
612bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain}
613bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
614bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary MorainByteString DeviceInfo::GetMACAddressFromKernel(int interface_index) const {
6154178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  const Info *info = GetInfo(interface_index);
6164178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  if (!info) {
6174178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain    return ByteString();
6184178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  }
6194178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain
6204178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  const int fd = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
621bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (fd < 0) {
622bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    LOG(ERROR) << __func__ << ": Unable to open socket: " << fd;
6234178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain    return ByteString();
624bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
6254178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain
6264178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  ScopedSocketCloser socket_closer(sockets_.get(), fd);
627bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  struct ifreq ifr;
628bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  memset(&ifr, 0, sizeof(ifr));
629bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  ifr.ifr_ifindex = interface_index;
6304178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  strcpy(ifr.ifr_ifrn.ifrn_name, info->name.c_str());
6314178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  int err = sockets_->Ioctl(fd, SIOCGIFHWADDR, &ifr);
632bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (err < 0) {
633bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    LOG(ERROR) << __func__ << ": Unable to read MAC address: " << errno;
6344178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain    return ByteString();
635bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
6364178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain
6374178023c4d627410777bdc259bfc7a31f2a4b8e9Gary Morain  return ByteString(ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
638e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov}
639e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov
6406950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewartbool DeviceInfo::GetMACAddressOfPeer(int interface_index,
6416950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart                                     const IPAddress &peer,
6426950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart                                     ByteString *mac_address) const {
6436950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  const Info *info = GetInfo(interface_index);
6446950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (!info || !peer.IsValid()) {
6456950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
6466950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
6476950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6486950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (peer.family() != IPAddress::kFamilyIPv4) {
6496950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    NOTIMPLEMENTED() << ": only implemented for IPv4";
6506950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
6516950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
6526950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6536950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  const int fd = sockets_->Socket(PF_INET, SOCK_DGRAM, 0);
6546950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (fd < 0) {
6556950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    LOG(ERROR) << __func__ << ": Unable to open socket: " << fd;
6566950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
6576950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
6586950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6596950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  ScopedSocketCloser socket_closer(sockets_.get(), fd);
6606950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  struct arpreq areq;
6616950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  memset(&areq, 0, sizeof(areq));
6626950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6636950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  strncpy(areq.arp_dev, info->name.c_str(), sizeof(areq.arp_dev) - 1);
6646950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  areq.arp_dev[sizeof(areq.arp_dev) - 1] = '\0';
6656950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6666950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  struct sockaddr_in *protocol_address =
6676950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart      reinterpret_cast<struct sockaddr_in *>(&areq.arp_pa);
6686950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  protocol_address->sin_family = AF_INET;
6696950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  CHECK_EQ(sizeof(protocol_address->sin_addr.s_addr), peer.GetLength());
6706950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  memcpy(&protocol_address->sin_addr.s_addr, peer.address().GetConstData(),
6716950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart         sizeof(protocol_address->sin_addr.s_addr));
6726950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6736950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  struct sockaddr_in *hardware_address =
6746950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart      reinterpret_cast<struct sockaddr_in *>(&areq.arp_ha);
6756950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  hardware_address->sin_family = ARPHRD_ETHER;
6766950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6776950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  int err = sockets_->Ioctl(fd, SIOCGARP, &areq);
6786950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (err < 0) {
6796950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    LOG(ERROR) << __func__ << ": Unable to perform ARP lookup: " << errno;
6806950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
6816950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
6826950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6836950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  ByteString peer_address(areq.arp_ha.sa_data, IFHWADDRLEN);
6846950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6856950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  if (peer_address.IsZero()) {
6866950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    LOG(INFO) << __func__ << ": ARP lookup is still in progress";
6876950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart    return false;
6886950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  }
6896950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6906950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  CHECK(mac_address);
6916950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  *mac_address = peer_address;
6926950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart  return true;
6936950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart}
6946950ba51e9a35b91687103fdc451e1539cdfb35dPaul Stewart
6959a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartbool DeviceInfo::GetAddresses(int interface_index,
6969a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              vector<AddressData> *addresses) const {
6979a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  const Info *info = GetInfo(interface_index);
6989a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!info) {
6999a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    return false;
7009a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
7019a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  *addresses = info->ip_addresses;
7029a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  return true;
7039a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
7049a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
7059a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartvoid DeviceInfo::FlushAddresses(int interface_index) const {
706fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(" << interface_index << ")";
7079a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  const Info *info = GetInfo(interface_index);
7089a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!info) {
7099a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    return;
7109a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
7116db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart  for (const auto &address_info : info->ip_addresses) {
7126db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart    if (address_info.address.family() == IPAddress::kFamilyIPv4 ||
7136db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart        (address_info.scope == RT_SCOPE_UNIVERSE &&
7146db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart         (address_info.flags & ~IFA_F_TEMPORARY) == 0)) {
7158c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << __func__ << ": removing ip address "
7166db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart                      << address_info.address.ToString()
7178c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " from interface " << interface_index;
7186db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart      rtnl_handler_->RemoveInterfaceAddress(interface_index,
7196db7b24348e69639e19cd6c408388b10d6ee54fePaul Stewart                                            address_info.address);
7209a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
7219a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
7229a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
7239a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
72405a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewartbool DeviceInfo::HasOtherAddress(
72505a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    int interface_index, const IPAddress &this_address) const {
72605a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  SLOG(Device, 3) << __func__ << "(" << interface_index << ")";
72705a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  const Info *info = GetInfo(interface_index);
72805a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  if (!info) {
72905a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    return false;
73005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  }
73105a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  bool has_other_address = false;
73205a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  bool has_this_address = false;
733a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  for (const auto &local_address : info->ip_addresses) {
734a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    if (local_address.address.family() != this_address.family()) {
73505a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      continue;
73605a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    }
737a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    if (local_address.address.address().Equals(this_address.address())) {
73805a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_this_address = true;
73905a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    } else if (this_address.family() == IPAddress::kFamilyIPv4) {
74005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_other_address = true;
741a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    } else if ((local_address.scope == RT_SCOPE_UNIVERSE &&
742a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart                (local_address.flags & IFA_F_TEMPORARY) == 0)) {
74305a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_other_address = true;
74405a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    }
74505a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  }
74605a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  return has_other_address && !has_this_address;
74705a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart}
74805a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart
749d55f6ae45047f984457508d78c70abcd837307eaPaul Stewartbool DeviceInfo::GetPrimaryIPv6Address(int interface_index,
750d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart                                       IPAddress *address) {
751d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  const Info *info = GetInfo(interface_index);
752d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  if (!info) {
753d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    return false;
754d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  }
755d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  bool has_temporary_address = false;
756d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  bool has_address = false;
757d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  for (const auto &local_address : info->ip_addresses) {
758d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    if (local_address.address.family() != IPAddress::kFamilyIPv6 ||
759d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart        local_address.scope != RT_SCOPE_UNIVERSE) {
760d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart      continue;
761d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    }
762d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
763d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    // Prefer temporary addresses to non-temporary addresses to match the
764d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    // kernel's preference.
765d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    bool is_temporary_address = ((local_address.flags & IFA_F_TEMPORARY) != 0);
766d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    if (has_temporary_address && !is_temporary_address) {
767d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart      continue;
768d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    }
769d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
770d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    *address = local_address.address;
771d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    has_temporary_address = is_temporary_address;
772d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    has_address = true;
773d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  }
774d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
775d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  return has_address;
776d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart}
777d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
778a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewartbool DeviceInfo::HasDirectConnectivityTo(
779a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    int interface_index, const IPAddress &address) const {
780a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  SLOG(Device, 3) << __func__ << "(" << interface_index << ")";
781a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  const Info *info = GetInfo(interface_index);
782a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  if (!info) {
783a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    return false;
784a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  }
785a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart
786a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  for (const auto &local_address : info->ip_addresses) {
787a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    if (local_address.address.family() == address.family() &&
788a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart        local_address.address.CanReachAddress(address)) {
789a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart      return true;
790a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart    }
791a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  }
792a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart
793a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart  return false;
794a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart}
795a0db0fff6ae05e1ba3facfdf3d5049ca1a277be4Paul Stewart
796e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkovbool DeviceInfo::GetFlags(int interface_index, unsigned int *flags) const {
797e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  const Info *info = GetInfo(interface_index);
798e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (!info) {
799e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    return false;
800e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  }
801e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  *flags = info->flags;
802e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return true;
803e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
804e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
8051ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartbool DeviceInfo::GetByteCounts(int interface_index,
8061ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                               uint64 *rx_bytes,
8071ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                               uint64 *tx_bytes) const {
8081ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  const Info *info = GetInfo(interface_index);
8091ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (!info) {
8101ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return false;
8111ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
8121ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  *rx_bytes = info->rx_bytes;
8131ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  *tx_bytes = info->tx_bytes;
8141ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  return true;
8151ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
8161ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
817ca6abd4635507fa5b8f4b8819a37819fb560c464Paul Stewartbool DeviceInfo::CreateTunnelInterface(string *interface_name) const {
818cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  int fd = HANDLE_EINTR(open(kTunDeviceName, O_RDWR));
819cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (fd < 0) {
820cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to open " << kTunDeviceName;
821cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
822cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
823cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  file_util::ScopedFD scoped_fd(&fd);
824cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
825cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  struct ifreq ifr;
826cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  memset(&ifr, 0, sizeof(ifr));
827cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
828cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (HANDLE_EINTR(ioctl(fd, TUNSETIFF, &ifr))) {
829cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to create tunnel interface";
830cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
831cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
832cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
833cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (HANDLE_EINTR(ioctl(fd, TUNSETPERSIST, 1))) {
834cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to set tunnel interface to be persistent";
835cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
836cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
837cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
838cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  *interface_name = string(ifr.ifr_name);
839cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
840cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  return true;
841cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart}
842cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
843ca6abd4635507fa5b8f4b8819a37819fb560c464Paul Stewartbool DeviceInfo::DeleteInterface(int interface_index) const {
844cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  return rtnl_handler_->RemoveInterface(interface_index);
845cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart}
846cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
847e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkovconst DeviceInfo::Info *DeviceInfo::GetInfo(int interface_index) const {
848e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  map<int, Info>::const_iterator iter = infos_.find(interface_index);
849e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (iter == infos_.end()) {
850e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    return NULL;
851e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  }
852e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return &iter->second;
853e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
854e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
855e6193c042652831cac90c3bbf2233877754b1eefDarin Petkovvoid DeviceInfo::RemoveInfo(int interface_index) {
856e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  map<int, Info>::iterator iter = infos_.find(interface_index);
857e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (iter != infos_.end()) {
858fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << "Removing info for device index: " << interface_index;
859e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    if (iter->second.device.get()) {
860e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov      manager_->DeregisterDevice(iter->second.device);
861e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    }
862f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    indices_.erase(iter->second.name);
863e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    infos_.erase(iter);
864050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    delayed_devices_.erase(interface_index);
86547009f8d7a6fbc257a1bb1288a01405d034bd13fmukesh agrawal  } else {
866fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << __func__ << ": Unknown device index: "
867fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                    << interface_index;
868b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
8690af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
8700af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
8712aa9707f114ab8166f45df5726bf05278df2aef6Chris Masonevoid DeviceInfo::LinkMsgHandler(const RTNLMessage &msg) {
8729a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink);
8739a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (msg.mode() == RTNLMessage::kModeAdd) {
8742aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    AddLinkMsgHandler(msg);
8759a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  } else if (msg.mode() == RTNLMessage::kModeDelete) {
8762aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    DelLinkMsgHandler(msg);
8772aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone  } else {
8782aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    NOTREACHED();
879b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
8800af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
8810af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
8829a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartvoid DeviceInfo::AddressMsgHandler(const RTNLMessage &msg) {
883fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__;
8849a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeAddress);
8859a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  int interface_index = msg.interface_index();
8869a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!ContainsKey(infos_, interface_index)) {
8878c116a90d3a3536430b808b15e73275060918434Paul Stewart    SLOG(Device, 2) << "Got advance address information for unknown index "
8888c116a90d3a3536430b808b15e73275060918434Paul Stewart                    << interface_index;
8898c116a90d3a3536430b808b15e73275060918434Paul Stewart    infos_[interface_index].has_addresses_only = true;
8909a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
8919a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  const RTNLMessage::AddressStatus &status = msg.address_status();
8929a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  IPAddress address(msg.family(),
893682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan                    msg.HasAttribute(IFA_LOCAL) ?
894682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan                    msg.GetAttribute(IFA_LOCAL) : msg.GetAttribute(IFA_ADDRESS),
8959a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                    status.prefix_len);
8969a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
897682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan  SLOG_IF(Device, 2, msg.HasAttribute(IFA_LOCAL))
898682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan      << "Found local address attribute for interface " << interface_index;
899682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan
9009a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  vector<AddressData> &address_list = infos_[interface_index].ip_addresses;
9019a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  vector<AddressData>::iterator iter;
9029a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  for (iter = address_list.begin(); iter != address_list.end(); ++iter) {
9039a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (address.Equals(iter->address)) {
9049a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      break;
9059a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
9069a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
9079a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (iter != address_list.end()) {
9089a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (msg.mode() == RTNLMessage::kModeDelete) {
909fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << "Delete address for interface " << interface_index;
9109a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      address_list.erase(iter);
9119a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else {
9129a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      iter->flags = status.flags;
9139a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      iter->scope = status.scope;
9149a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
9159a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  } else if (msg.mode() == RTNLMessage::kModeAdd) {
9169a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    address_list.push_back(AddressData(address, status.flags, status.scope));
9178c116a90d3a3536430b808b15e73275060918434Paul Stewart    SLOG(Device, 2) << "Add address " << address.ToString()
9188c116a90d3a3536430b808b15e73275060918434Paul Stewart                    << " for interface " << interface_index;
9199a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
920d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart
921d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  DeviceRefPtr device = GetDevice(interface_index);
922d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  if (device && address.family() == IPAddress::kFamilyIPv6 &&
923d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart      status.scope == RT_SCOPE_UNIVERSE) {
924d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart    device->OnIPv6AddressChanged();
925d55f6ae45047f984457508d78c70abcd837307eaPaul Stewart  }
9269a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
9279a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
928050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartvoid DeviceInfo::DelayDeviceCreation(int interface_index) {
929050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.insert(interface_index);
930050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_callback_.Reset(
931050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      Bind(&DeviceInfo::DelayedDeviceCreationTask, AsWeakPtr()));
932050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  dispatcher_->PostDelayedTask(delayed_devices_callback_.callback(),
933050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                               kDelayedDeviceCreationSeconds * 1000);
934050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart}
935050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
936050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart// Re-evaluate the technology type for each delayed device.
937050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartvoid DeviceInfo::DelayedDeviceCreationTask() {
938050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  while (!delayed_devices_.empty()) {
939050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    set<int>::iterator it = delayed_devices_.begin();
940050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    int dev_index = *it;
941050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    delayed_devices_.erase(it);
942050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
943050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(ContainsKey(infos_, dev_index));
944050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(!GetDevice(dev_index));
945050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
946050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    const string &link_name = infos_[dev_index].name;
947050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    Technology::Identifier technology = GetDeviceTechnology(link_name);
948050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
949050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    if (technology == Technology::kCDCEthernet) {
950050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(INFO) << "In " << __func__ << ": device " << link_name
951050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                << " is now assumed to be regular Ethernet.";
952050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      technology = Technology::kEthernet;
953050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    } else if (technology != Technology::kCellular) {
954050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(WARNING) << "In " << __func__ << ": device " << link_name
955050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                   << " is unexpected technology "
956050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                   << Technology::NameFromIdentifier(technology);
957050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
958050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    string address =
959050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart        StringToLowerASCII(infos_[dev_index].mac_address.HexEncode());
960050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(!address.empty());
961050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
962050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DeviceRefPtr device = CreateDevice(link_name, address, dev_index,
963050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                                       technology);
964050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    if (device) {
965050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      RegisterDevice(device);
966050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
967050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  }
968050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart}
969050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
9701ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartvoid DeviceInfo::RetrieveLinkStatistics(int interface_index,
9711ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                                        const RTNLMessage &msg) {
9721ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (!msg.HasAttribute(IFLA_STATS64)) {
9731ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return;
9741ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
9751ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  ByteString stats_bytes(msg.GetAttribute(IFLA_STATS64));
9761ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  struct rtnl_link_stats64 stats;
9771ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (stats_bytes.GetLength() < sizeof(stats)) {
9781ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    LOG(WARNING) << "Link statistics size is too small: "
9791ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                 << stats_bytes.GetLength() << " < " << sizeof(stats);
9801ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return;
9811ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
9821ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
9831ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  memcpy(&stats, stats_bytes.GetConstData(), sizeof(stats));
9841ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  SLOG(Device, 2) << "Link statistics for "
9851ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                  << " interface index " << interface_index << ": "
9861ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                  << "receive: " << stats.rx_bytes << "; "
9871ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                  << "transmit: " << stats.tx_bytes << ".";
9881ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  infos_[interface_index].rx_bytes = stats.rx_bytes;
9891ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  infos_[interface_index].tx_bytes = stats.tx_bytes;
9901ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
9911ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
9921ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartvoid DeviceInfo::RequestLinkStatistics() {
9931ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
9941ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  dispatcher_->PostDelayedTask(request_link_statistics_callback_.callback(),
995b061f89e7088c7fba50b49ee5ac876619c9e8a7eBen Chan                               kRequestLinkStatisticsIntervalMilliseconds);
9961ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
9971ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
9982ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewartvoid DeviceInfo::GetWiFiInterfaceInfo(int interface_index) {
9992ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  GetInterfaceMessage msg;
10002ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (!msg.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
10012ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart                                              interface_index)) {
10022ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Unable to set interface index attribute for "
10032ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart                  "GetInterface message.  Interface type cannot be "
10042ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart                  "determined!";
10052ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
10062ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
10077347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  netlink_manager_->SendNl80211Message(
10087347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie      &msg,
10097347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie      Bind(&DeviceInfo::OnWiFiInterfaceInfoReceived, AsWeakPtr()),
10107347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie      Bind(&NetlinkManager::OnNetlinkMessageError));
10112ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart}
10122ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart
10137347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrievoid DeviceInfo::OnWiFiInterfaceInfoReceived(const Nl80211Message &msg) {
10147347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  if (msg.command() != NL80211_CMD_NEW_INTERFACE) {
10152ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Message is not a new interface response";
10162ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
10172ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
10182ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart
10192ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  uint32_t interface_index;
10207347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFINDEX,
10217347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie                                                    &interface_index)) {
10222ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Message contains no interface index";
10232ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
10242ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
10252ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  uint32_t interface_type;
10267347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFTYPE,
10277347bf2b466ae8058e47b29aaf0583390405d866Wade Guthrie                                                    &interface_type)) {
10282ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Message contains no interface type";
10292ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
10302ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
10312ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  const Info *info = GetInfo(interface_index);
10322ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (!info) {
10332ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Could not find device info for interface index "
10342ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart               << interface_index;
10352ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
10362ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
10372ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (info->device) {
10382ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(ERROR) << "Device already created for interface index "
10392ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart               << interface_index;
10402ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
10412ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
10422ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  if (interface_type != NL80211_IFTYPE_STATION) {
10432ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    LOG(INFO) << "Ignoring WiFi device "
10442ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << info->name
10452ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << " at interface index "
10462ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << interface_index
10472ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << " since it is not in station mode.";
10482ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart    return;
10492ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  }
10502ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  LOG(INFO) << "Creating WiFi device for station mode interface "
10512ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << info->name
10522ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << " at interface index "
10532ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart              << interface_index;
10542ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  string address = StringToLowerASCII(info->mac_address.HexEncode());
10552ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  DeviceRefPtr device =
10562ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart      new WiFi(control_interface_, dispatcher_, metrics_, manager_,
10572ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart               info->name, address, interface_index);
10582ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  device->EnableIPv6Privacy();
10592ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart  RegisterDevice(device);
10602ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart}
10612ddf2c63751546aa554335a6733314a3859d5c2ePaul Stewart
10620af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}  // namespace shill
1063