device_info.cc revision 05a42c23f1d37daa8689fc4240034e62ed89f8fc
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>
25487b8bfc46a91e29bb23aaf3c59cfe67033bfc8bChris Masone#include <base/logging.h>
26487b8bfc46a91e29bb23aaf3c59cfe67033bfc8bChris Masone#include <base/memory/scoped_ptr.h>
273e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/stl_util.h>
282001a42edf1d42ec828a9baf3157496c20fefd49Paul Stewart#include <base/string_number_conversions.h>
29877ff9894e21c4c78b63777025f6c8d577ccd855Chris Masone#include <base/string_util.h>
30b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart#include <base/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"
36b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart#include "shill/manager.h"
378c116a90d3a3536430b808b15e73275060918434Paul Stewart#include "shill/routing_table.h"
38a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart#include "shill/rtnl_handler.h"
39a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart#include "shill/rtnl_listener.h"
402aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone#include "shill/rtnl_message.h"
41fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan#include "shill/scope_logger.h"
42487b8bfc46a91e29bb23aaf3c59cfe67033bfc8bChris Masone#include "shill/service.h"
4393a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal#include "shill/virtio_ethernet.h"
44b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart#include "shill/wifi.h"
450af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
463e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Bind;
478f1c835d879f82261a08257eb6f9677e6be51fdaThieu Leusing base::StringPrintf;
483e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbroodusing base::Unretained;
49e6193c042652831cac90c3bbf2233877754b1eefDarin Petkovusing std::map;
50050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartusing std::set;
510af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewartusing std::string;
529a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartusing std::vector;
530af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
540af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewartnamespace shill {
55b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
56b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart// static
57abc5403270e26fa898181301911a905758f8d758Jason Glasgowconst char DeviceInfo::kModemPseudoDeviceNamePrefix[] = "pseudomodem";
58ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kDeviceInfoRoot[] = "/sys/class/net";
594e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chanconst char DeviceInfo::kDriverCdcEther[] = "cdc_ether";
604e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chanconst char DeviceInfo::kDriverGdmWiMax[] = "gdm_wimax";
6193a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawalconst char DeviceInfo::kDriverVirtioNet[] = "virtio_net";
62ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceUevent[] = "uevent";
639364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewartconst char DeviceInfo::kInterfaceUeventWifiSignature[] = "DEVTYPE=wlan\n";
64ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceDevice[] = "device";
65ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceDriver[] = "device/driver";
66ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceTunFlags[] = "tun_flags";
67ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartconst char DeviceInfo::kInterfaceType[] = "type";
68b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewartconst char *DeviceInfo::kModemDrivers[] = {
69b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    "gobi",
70b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    "QCUSBNet2k",
718f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le    "GobiNet"
72b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart};
73cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewartconst char DeviceInfo::kTunDeviceName[] = "/dev/net/tun";
74050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartconst int DeviceInfo::kDelayedDeviceCreationSeconds = 5;
751ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartconst int DeviceInfo::kRequestLinkStatisticsIntervalSeconds = 60;
76b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
77b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul StewartDeviceInfo::DeviceInfo(ControlInterface *control_interface,
78b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart                       EventDispatcher *dispatcher,
793426c8fc7a3943f2d8fcb2ec78f0593088b42bedThieu Le                       Metrics *metrics,
80b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart                       Manager *manager)
81a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart    : control_interface_(control_interface),
82a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart      dispatcher_(dispatcher),
833426c8fc7a3943f2d8fcb2ec78f0593088b42bedThieu Le      metrics_(metrics),
84a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart      manager_(manager),
853e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      link_callback_(Bind(&DeviceInfo::LinkMsgHandler, Unretained(this))),
863e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      address_callback_(Bind(&DeviceInfo::AddressMsgHandler, Unretained(this))),
879a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      link_listener_(NULL),
889a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      address_listener_(NULL),
89ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      device_info_root_(kDeviceInfoRoot),
908c116a90d3a3536430b808b15e73275060918434Paul Stewart      routing_table_(RoutingTable::GetInstance()),
919a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      rtnl_handler_(RTNLHandler::GetInstance()) {
920af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
930af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
94a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul StewartDeviceInfo::~DeviceInfo() {}
950af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
968f317b600a218afe05f2d73c59204bb98269a950mukesh agrawalvoid DeviceInfo::AddDeviceToBlackList(const string &device_name) {
978f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal  black_list_.insert(device_name);
988f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal}
998f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal
1005e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbroodbool DeviceInfo::IsDeviceBlackListed(const string &device_name) {
1015e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood  return ContainsKey(black_list_, device_name);
1025e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood}
1035e628a5c722c196ad240af0ff3c717e9613d3ef5Eric Shienbrood
104a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewartvoid DeviceInfo::Start() {
105a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart  link_listener_.reset(
1063e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestLink, link_callback_));
1079a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  address_listener_.reset(
1083e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood      new RTNLListener(RTNLHandler::kRequestAddr, address_callback_));
1099a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink |
1109a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                             RTNLHandler::kRequestAddr);
1111ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  request_link_statistics_callback_.Reset(
1121ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart      Bind(&DeviceInfo::RequestLinkStatistics, AsWeakPtr()));
1131ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  dispatcher_->PostDelayedTask(request_link_statistics_callback_.callback(),
1141ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                               kRequestLinkStatisticsIntervalSeconds * 1000);
1150af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1160af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
117a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewartvoid DeviceInfo::Stop() {
1189a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  link_listener_.reset();
1199a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  address_listener_.reset();
1208c116a90d3a3536430b808b15e73275060918434Paul Stewart  infos_.clear();
1211ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  request_link_statistics_callback_.Cancel();
122050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_callback_.Cancel();
123050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.clear();
1240af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
1250af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
1266f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkovvoid DeviceInfo::RegisterDevice(const DeviceRefPtr &device) {
127fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(" << device->link_name() << ", "
128fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << device->interface_index() << ")";
129050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.erase(device->interface_index());
130e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  CHECK(!GetDevice(device->interface_index()).get());
131e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  infos_[device->interface_index()].device = device;
132da798623389b981130cd1922f880736f1e0e36baJoshua Kroll  if ((device->technology() == Technology::kCellular) ||
133da798623389b981130cd1922f880736f1e0e36baJoshua Kroll      (device->technology() == Technology::kEthernet) ||
134da798623389b981130cd1922f880736f1e0e36baJoshua Kroll      (device->technology() == Technology::kWifi) ||
135da798623389b981130cd1922f880736f1e0e36baJoshua Kroll      (device->technology() == Technology::kWiMax)) {
1366f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov    manager_->RegisterDevice(device);
1376f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov  }
1386f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov}
1396f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov
140e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgowvoid DeviceInfo::DeregisterDevice(const DeviceRefPtr &device) {
141e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  int interface_index = device->interface_index();
142e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
143fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(" << device->link_name() << ", "
144fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << interface_index << ")";
145da798623389b981130cd1922f880736f1e0e36baJoshua Kroll  CHECK((device->technology() == Technology::kCellular) ||
146da798623389b981130cd1922f880736f1e0e36baJoshua Kroll        (device->technology() == Technology::kWiMax));
147e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
148e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  // Release reference to the device
149e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  map<int, Info>::iterator iter = infos_.find(interface_index);
150e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  if (iter != infos_.end()) {
151fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << "Removing device from info for index: "
152fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                    << interface_index;
153e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    manager_->DeregisterDevice(device);
154e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    // Release the reference to the device, but maintain the mapping
155e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    // for the index.  That will be cleaned up by an RTNL message.
156e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow    iter->second.device = NULL;
157e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow  }
158e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow}
159e908949fa87c32ed97073d3e79fb7f450541cb95Jason Glasgow
160ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul StewartFilePath DeviceInfo::GetDeviceInfoPath(const string &iface_name,
161ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                       const string &path_name) {
162ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  return device_info_root_.Append(iface_name).Append(path_name);
163ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
164ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
165ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartbool DeviceInfo::GetDeviceInfoContents(const string &iface_name,
166ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                       const string &path_name,
167ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                       string *contents_out) {
168ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  return file_util::ReadFileToString(GetDeviceInfoPath(iface_name, path_name),
169ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                     contents_out);
170ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
171ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewartbool DeviceInfo::GetDeviceInfoSymbolicLink(const string &iface_name,
1724e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                                           const string &path_name,
1734e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                                           FilePath *path_out) {
174ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  return file_util::ReadSymbolicLink(GetDeviceInfoPath(iface_name, path_name),
175ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                     path_out);
176ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart}
177ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
178fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul StewartTechnology::Identifier DeviceInfo::GetDeviceTechnology(
179fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    const string &iface_name) {
180ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  string type_string;
181ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  int arp_type = ARPHRD_VOID;;
182ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (GetDeviceInfoContents(iface_name, kInterfaceType, &type_string) &&
183ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      TrimString(type_string, "\n", &type_string) &&
184ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      !base::StringToInt(type_string, &arp_type)) {
185ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    arp_type = ARPHRD_VOID;
186ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  }
187ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart
1889364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  string contents;
189ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (!GetDeviceInfoContents(iface_name, kInterfaceUevent, &contents)) {
190050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    LOG(INFO) << StringPrintf("%s: device %s has no uevent file",
191050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                              __func__, iface_name.c_str());
192fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    return Technology::kUnknown;
1939364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
194b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
1958f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // If the "uevent" file contains the string "DEVTYPE=wlan\n" at the
1968f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // start of the file or after a newline, we can safely assume this
1978f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // is a wifi device.
1989364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  if (contents.find(kInterfaceUeventWifiSignature) != string::npos) {
199fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2)
200fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan        << StringPrintf("%s: device %s has wifi signature in uevent file",
201fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                        __func__, iface_name.c_str());
202ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_IEEE80211_RADIOTAP) {
203fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << StringPrintf("%s: wifi device %s is in monitor mode",
204fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                      __func__, iface_name.c_str());
2052001a42edf1d42ec828a9baf3157496c20fefd49Paul Stewart      return Technology::kWiFiMonitor;
2062001a42edf1d42ec828a9baf3157496c20fefd49Paul Stewart    }
207fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart    return Technology::kWifi;
2089364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
209b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2107904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  // Special case for pseudo modems which are used for testing
2117904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  if (iface_name.find(kModemPseudoDeviceNamePrefix) == 0) {
2127904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow    SLOG(Device, 2) << StringPrintf(
2137904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow        "%s: device %s is a pseudo modem for testing",
2147904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow        __func__, iface_name.c_str());
2157904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow    return Technology::kCellular;
2167904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow  }
2177904d1443656999fd0a7faaf247aad05a7b3e0a6Jason Glasgow
2189364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  FilePath driver_path;
219ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  if (!GetDeviceInfoSymbolicLink(iface_name, kInterfaceDriver, &driver_path)) {
220fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s has no device symlink",
221fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                    __func__, iface_name.c_str());
222ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_LOOPBACK) {
223fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << StringPrintf("%s: device %s is a loopback device",
224fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                      __func__, iface_name.c_str());
225e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart      return Technology::kLoopback;
226e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart    }
227ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (arp_type == ARPHRD_PPP) {
228ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      SLOG(Device, 2) << StringPrintf("%s: device %s is a ppp device",
229ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart                                      __func__, iface_name.c_str());
230ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart      return Technology::kPPP;
231ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    }
232ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    string tun_flags_str;
233cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    int tun_flags = 0;
234ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    if (GetDeviceInfoContents(iface_name, kInterfaceTunFlags, &tun_flags_str) &&
235ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart        TrimString(tun_flags_str, "\n", &tun_flags_str) &&
236ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart        base::HexStringToInt(tun_flags_str, &tun_flags) &&
237cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart        (tun_flags & IFF_TUN)) {
238fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << StringPrintf("%s: device %s is tun device",
239fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                      __func__, iface_name.c_str());
240cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      return Technology::kTunnel;
241cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    }
242e81eb700f66563cb695b6e3682f20ac5a0cdb8c0Paul Stewart    return Technology::kUnknown;
2439364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  }
244b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2459364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart  string driver_name(driver_path.BaseName().value());
2468f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // See if driver for this interface is in a list of known modem driver names.
2478f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  for (size_t modem_idx = 0; modem_idx < arraysize(kModemDrivers);
2488f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le       ++modem_idx) {
2499364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart    if (driver_name == kModemDrivers[modem_idx]) {
250fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2)
251fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan          << StringPrintf("%s: device %s is matched with modem driver %s",
252fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                          __func__, iface_name.c_str(), driver_name.c_str());
2539364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart      return Technology::kCellular;
2549364c4c9a1e1f4bbb59c8d32ac97c928505fc8cbPaul Stewart    }
255b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
2560af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
2574e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan  if (driver_name == kDriverGdmWiMax) {
2584e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s is a WiMAX device",
2594e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                                    __func__, iface_name.c_str());
2604e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    return Technology::kWiMax;
2614e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan  }
2624e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan
2638f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // For cdc_ether devices, make sure it's a modem because this driver
2648f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // can be used for other ethernet devices.
265050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  if (driver_name == kDriverCdcEther) {
266050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    if (IsCdcEtherModemDevice(iface_name)) {
267050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(INFO) << StringPrintf("%s: device %s is a modem cdc_ether "
268050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                                "device", __func__, iface_name.c_str());
269050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      return Technology::kCellular;
270050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
271050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    SLOG(Device, 2) << StringPrintf("%s: device %s is a cdc_ether "
272050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                                    "device", __func__, iface_name.c_str());
273050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    return Technology::kCDCEthernet;
2748f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
275abc5403270e26fa898181301911a905758f8d758Jason Glasgow
27693a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  // Special case for the virtio driver, used when run under KVM. See also
27793a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  // the comment in VirtioEthernet::Start.
27893a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  if (driver_name == kDriverVirtioNet) {
279fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s is virtio ethernet",
280fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                    __func__, iface_name.c_str());
28193a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal    return Technology::kVirtioEthernet;
28293a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal  }
28393a29ed675f5c75250d09e192d72fe6804c10111mukesh agrawal
284fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << StringPrintf("%s: device %s, with driver %s, "
285fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                  "is defaulted to type ethernet",
286fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                  __func__, iface_name.c_str(),
287fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                  driver_name.c_str());
288fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart  return Technology::kEthernet;
289b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart}
290b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
2918f1c835d879f82261a08257eb6f9677e6be51fdaThieu Lebool DeviceInfo::IsCdcEtherModemDevice(const std::string &iface_name) {
2928f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // A cdc_ether device is a modem device if it also exposes tty interfaces.
2938f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // To determine this, we look for the existence of the tty interface in the
2948f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // USB device sysfs tree.
2958f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
2968f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // A typical sysfs dir hierarchy for a cdc_ether modem USB device is as
2978f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // follows:
2988f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
2998f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //   /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2
3008f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.0
3018f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       tty
3028f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         ttyACM0
3038f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.1
3048f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       net
3058f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         usb0
3068f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //     1-2:1.2
3078f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       tty
3088f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //         ttyACM1
3098f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //       ...
3108f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  //
3118f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // /sys/class/net/usb0/device symlinks to
3128f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2/1-2:1.1
313b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  //
314b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // Note that some modem devices have the tty directory one level deeper
315b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // (eg. E362), so the device tree for the tty interface is:
316b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb/1-2/1-2:1.0/ttyUSB0/tty/ttyUSB0
3178f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
318ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart  FilePath device_file = GetDeviceInfoPath(iface_name, kInterfaceDevice);
3198f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  FilePath device_path;
3208f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  if (!file_util::ReadSymbolicLink(device_file, &device_path)) {
321fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << StringPrintf("%s: device %s has no device symlink",
322fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                                    __func__, iface_name.c_str());
3238f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le    return false;
3248f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
3258f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  if (!device_path.IsAbsolute()) {
3268f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le    device_path = device_file.DirName().Append(device_path);
3278f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le    file_util::AbsolutePath(&device_path);
3288f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
3298f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
3308f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // Look for tty interface by enumerating all directories under the parent
331b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // USB device and see if there's a subdirectory "tty" inside.  In other
332b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // words, using the example dir hierarchy above, find
333b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  // /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2/.../tty.
3348f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  // If this exists, then this is a modem device.
335b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  return HasSubdir(device_path.DirName(), FilePath("tty"));
3368f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le}
3378f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
3388f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le// static
339b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Lebool DeviceInfo::HasSubdir(const FilePath &base_dir, const FilePath &subdir) {
340b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  file_util::FileEnumerator::FileType type =
341b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le      static_cast<file_util::FileEnumerator::FileType>(
342b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le          file_util::FileEnumerator::DIRECTORIES |
343b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le          file_util::FileEnumerator::SHOW_SYM_LINKS);
344b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le  file_util::FileEnumerator dir_enum(base_dir, true, type);
3458f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  for (FilePath curr_dir = dir_enum.Next(); !curr_dir.empty();
3468f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le       curr_dir = dir_enum.Next()) {
347b27beee2e85a1ad3d68a1218c8c4fef4214626e8Thieu Le    if (curr_dir.BaseName() == subdir)
3488f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le      return true;
3498f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  }
3508f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le  return false;
3518f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le}
3528f1c835d879f82261a08257eb6f9677e6be51fdaThieu Le
3538c116a90d3a3536430b808b15e73275060918434Paul StewartDeviceRefPtr DeviceInfo::CreateDevice(const string &link_name,
3548c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      const string &address,
3558c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      int interface_index,
3568c116a90d3a3536430b808b15e73275060918434Paul Stewart                                      Technology::Identifier technology) {
3578c116a90d3a3536430b808b15e73275060918434Paul Stewart  DeviceRefPtr device;
358050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.erase(interface_index);
3598c116a90d3a3536430b808b15e73275060918434Paul Stewart
3608c116a90d3a3536430b808b15e73275060918434Paul Stewart  switch (technology) {
3618c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kCellular:
3628c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Cellular devices are managed by ModemInfo.
3638c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << "Cellular link " << link_name
3648c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " at index " << interface_index
3658c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " -- notifying ModemInfo.";
366bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
367bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      // The MAC address provided by RTNL is not reliable for Gobi 2K modems.
368bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      // Clear it here, and it will be fetched from the kernel is
369bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      // GetMacAddress().
370bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain      infos_[interface_index].mac_address.Clear();
3718c116a90d3a3536430b808b15e73275060918434Paul Stewart      manager_->modem_info()->OnDeviceInfoAvailable(link_name);
3728c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
3738c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kEthernet:
3748c116a90d3a3536430b808b15e73275060918434Paul Stewart      device = new Ethernet(control_interface_, dispatcher_, metrics_,
3758c116a90d3a3536430b808b15e73275060918434Paul Stewart                            manager_, link_name, address, interface_index);
3768c116a90d3a3536430b808b15e73275060918434Paul Stewart      device->EnableIPv6Privacy();
3778c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
3788c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kVirtioEthernet:
3798c116a90d3a3536430b808b15e73275060918434Paul Stewart      device = new VirtioEthernet(control_interface_, dispatcher_, metrics_,
3808c116a90d3a3536430b808b15e73275060918434Paul Stewart                                  manager_, link_name, address,
3818c116a90d3a3536430b808b15e73275060918434Paul Stewart                                  interface_index);
3828c116a90d3a3536430b808b15e73275060918434Paul Stewart      device->EnableIPv6Privacy();
3838c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
3848c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kWifi:
3858c116a90d3a3536430b808b15e73275060918434Paul Stewart      device = new WiFi(control_interface_, dispatcher_, metrics_, manager_,
3868c116a90d3a3536430b808b15e73275060918434Paul Stewart                        link_name, address, interface_index);
3878c116a90d3a3536430b808b15e73275060918434Paul Stewart      device->EnableIPv6Privacy();
3888c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
3894e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    case Technology::kWiMax:
390e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      // WiMax devices are managed by WiMaxProvider.
391e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      SLOG(Device, 2) << "WiMax link " << link_name
392e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov                      << " at index " << interface_index
393e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov                      << " -- notifying WiMaxProvider.";
394e4b270274cba2a1976c7be6c733bd899e009c1d1Darin Petkov      manager_->wimax_provider()->OnDeviceInfoAvailable(link_name);
3954e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan      break;
3968c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kPPP:
3978c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kTunnel:
3988c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Tunnel and PPP devices are managed by the VPN code (PPP for
3998c116a90d3a3536430b808b15e73275060918434Paul Stewart      // l2tpipsec).  Notify the VPN Provider of the interface's presence.
4008c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Since CreateDevice is only called once in the lifetime of an
4018c116a90d3a3536430b808b15e73275060918434Paul Stewart      // interface index, this notification will only occur the first
4028c116a90d3a3536430b808b15e73275060918434Paul Stewart      // time the device is seen.
4038c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << "Tunnel / PPP link " << link_name
4048c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " at index " << interface_index
4058c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " -- notifying VPNProvider.";
4068c116a90d3a3536430b808b15e73275060918434Paul Stewart      if (!manager_->vpn_provider()->OnDeviceInfoAvailable(link_name,
4078c116a90d3a3536430b808b15e73275060918434Paul Stewart                                                           interface_index) &&
4088c116a90d3a3536430b808b15e73275060918434Paul Stewart          technology == Technology::kTunnel) {
4098c116a90d3a3536430b808b15e73275060918434Paul Stewart        // If VPN does not know anything about this tunnel, it is probably
4108c116a90d3a3536430b808b15e73275060918434Paul Stewart        // left over from a previous instance and should not exist.
4118c116a90d3a3536430b808b15e73275060918434Paul Stewart        SLOG(Device, 2) << "Tunnel link is unused.  Deleting.";
4128c116a90d3a3536430b808b15e73275060918434Paul Stewart        DeleteInterface(interface_index);
4138c116a90d3a3536430b808b15e73275060918434Paul Stewart      }
4148c116a90d3a3536430b808b15e73275060918434Paul Stewart      break;
4158c116a90d3a3536430b808b15e73275060918434Paul Stewart    case Technology::kLoopback:
4168c116a90d3a3536430b808b15e73275060918434Paul Stewart      // Loopback devices are largely ignored, but we should make sure the
4178c116a90d3a3536430b808b15e73275060918434Paul Stewart      // link is enabled.
4188c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << "Bringing up loopback device " << link_name
4198c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " at index " << interface_index;
4208c116a90d3a3536430b808b15e73275060918434Paul Stewart      rtnl_handler_->SetInterfaceFlags(interface_index, IFF_UP, IFF_UP);
4218c116a90d3a3536430b808b15e73275060918434Paul Stewart      return NULL;
422050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    case Technology::kCDCEthernet:
423050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // CDCEnternet devices are of indeterminate type when they are
424050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // initially created.  Some time later, tty devices may or may
425050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // not appear under the same USB device root, which will identify
426050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // it as a modem.  Alternatively, ModemManager may discover the
427050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // device and create and register a Cellular device.  In either
428050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // case, we should delay creating a Device until we can make a
429050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      // better determination of what type this Device should be.
430050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(INFO) << "Delaying creation of device for " << link_name
431050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                << " at index " << interface_index;
432050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      DelayDeviceCreation(interface_index);
433050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      return NULL;
4348c116a90d3a3536430b808b15e73275060918434Paul Stewart    default:
4358c116a90d3a3536430b808b15e73275060918434Paul Stewart      // We will not manage this device in shill.  Do not create a device
4368c116a90d3a3536430b808b15e73275060918434Paul Stewart      // object or do anything to change its state.  We create a stub object
4378c116a90d3a3536430b808b15e73275060918434Paul Stewart      // which is useful for testing.
4388c116a90d3a3536430b808b15e73275060918434Paul Stewart      return new DeviceStub(control_interface_, dispatcher_, metrics_,
4398c116a90d3a3536430b808b15e73275060918434Paul Stewart                            manager_, link_name, address, interface_index,
4404e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan                            technology);
4418c116a90d3a3536430b808b15e73275060918434Paul Stewart  }
4428c116a90d3a3536430b808b15e73275060918434Paul Stewart
4438c116a90d3a3536430b808b15e73275060918434Paul Stewart  // Reset the routing table and addresses.
4448c116a90d3a3536430b808b15e73275060918434Paul Stewart  routing_table_->FlushRoutes(interface_index);
4458c116a90d3a3536430b808b15e73275060918434Paul Stewart  FlushAddresses(interface_index);
4468c116a90d3a3536430b808b15e73275060918434Paul Stewart
4478c116a90d3a3536430b808b15e73275060918434Paul Stewart  return device;
4488c116a90d3a3536430b808b15e73275060918434Paul Stewart}
4498c116a90d3a3536430b808b15e73275060918434Paul Stewart
4502aa9707f114ab8166f45df5726bf05278df2aef6Chris Masonevoid DeviceInfo::AddLinkMsgHandler(const RTNLMessage &msg) {
4519a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
4529a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart         msg.mode() == RTNLMessage::kModeAdd);
4532aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone  int dev_index = msg.interface_index();
454fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart  Technology::Identifier technology = Technology::kUnknown;
455b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
456e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  unsigned int flags = msg.link_status().flags;
457e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  unsigned int change = msg.link_status().change;
4588c116a90d3a3536430b808b15e73275060918434Paul Stewart  bool new_device =
4598c116a90d3a3536430b808b15e73275060918434Paul Stewart      !ContainsKey(infos_, dev_index) || infos_[dev_index].has_addresses_only;
460fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(index=" << dev_index
461fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << std::showbase << std::hex
462fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", flags=" << flags << ", change=" << change << ")"
463fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << std::dec << std::noshowbase
464fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", new_device=" << new_device;
4658c116a90d3a3536430b808b15e73275060918434Paul Stewart  infos_[dev_index].has_addresses_only = false;
466e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  infos_[dev_index].flags = flags;
467f1ce5d27adbfcaf9c46e650252b46e02b0d8addaPaul Stewart
4681ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  RetrieveLinkStatistics(dev_index, msg);
4691ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
4706f9eaa30b850ee4a22e71fd1b6ab13c873ec7110Darin Petkov  DeviceRefPtr device = GetDevice(dev_index);
4718c116a90d3a3536430b808b15e73275060918434Paul Stewart  if (new_device) {
4728c116a90d3a3536430b808b15e73275060918434Paul Stewart    CHECK(!device);
4732aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    if (!msg.HasAttribute(IFLA_IFNAME)) {
4742aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone      LOG(ERROR) << "Add Link message does not have IFLA_IFNAME!";
4752aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone      return;
476b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    }
4772aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    ByteString b(msg.GetAttribute(IFLA_IFNAME));
4782aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    string link_name(reinterpret_cast<const char*>(b.GetConstData()));
479fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << "add link index "  << dev_index << " name " << link_name;
480f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    infos_[dev_index].name = link_name;
481f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    indices_[link_name] = dev_index;
482a3c56f9f49e6c72ff55cc1224cccd60538e9b788Paul Stewart
4832aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    if (!link_name.empty()) {
4848f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      if (ContainsKey(black_list_, link_name)) {
485fdd1607e26db6c10585f7eefa0e02546274ea8f5Paul Stewart        technology = Technology::kBlacklisted;
4868f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      } else {
4878f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal        technology = GetDeviceTechnology(link_name);
4888f317b600a218afe05f2d73c59204bb98269a950mukesh agrawal      }
489633ac6f0d56a62f8fd21ba7d9a15818fe080fb2fDarin Petkov    }
490cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    string address;
491cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    if (msg.HasAttribute(IFLA_ADDRESS)) {
492cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      infos_[dev_index].mac_address = msg.GetAttribute(IFLA_ADDRESS);
493cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      address = StringToLowerASCII(infos_[dev_index].mac_address.HexEncode());
494fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << "link index " << dev_index << " address "
495fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                      << infos_[dev_index].mac_address.HexEncode();
496ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart    } else if (technology != Technology::kTunnel &&
497ca876ee6b11b38a3df7a8ab03efe9ed0bcab41d8Paul Stewart               technology != Technology::kPPP) {
498cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      LOG(ERROR) << "Add Link message does not have IFLA_ADDRESS!";
499cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart      return;
500cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    }
5018c116a90d3a3536430b808b15e73275060918434Paul Stewart    device = CreateDevice(link_name, address, dev_index, technology);
5028c116a90d3a3536430b808b15e73275060918434Paul Stewart    if (device) {
5038c116a90d3a3536430b808b15e73275060918434Paul Stewart      RegisterDevice(device);
504b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart    }
505b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
5068c116a90d3a3536430b808b15e73275060918434Paul Stewart  if (device) {
5078c116a90d3a3536430b808b15e73275060918434Paul Stewart    device->LinkEvent(flags, change);
5088c116a90d3a3536430b808b15e73275060918434Paul Stewart  }
509b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart}
510b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
5112aa9707f114ab8166f45df5726bf05278df2aef6Chris Masonevoid DeviceInfo::DelLinkMsgHandler(const RTNLMessage &msg) {
512fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(index=" << msg.interface_index() << ")";
51347009f8d7a6fbc257a1bb1288a01405d034bd13fmukesh agrawal
5149a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink &&
5159a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart         msg.mode() == RTNLMessage::kModeDelete);
516fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(index=" << msg.interface_index()
517fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << std::showbase << std::hex
518fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", flags=" << msg.link_status().flags
519fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                  << ", change=" << msg.link_status().change << ")";
520e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  RemoveInfo(msg.interface_index());
521e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
522e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
523e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin PetkovDeviceRefPtr DeviceInfo::GetDevice(int interface_index) const {
524e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  const Info *info = GetInfo(interface_index);
525e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return info ? info->device : NULL;
52667d8ecfd1d6ff5ea75b9d5c7167d9c16891d3d4bDarin Petkov}
527b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart
528f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkovint DeviceInfo::GetIndex(const string &interface_name) const {
529f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  map<string, int>::const_iterator it = indices_.find(interface_name);
530f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  return it == indices_.end() ? -1 : it->second;
531f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov}
532f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov
5333285296e6624fa0b1b10699f2fa6466d4be10742Paul Stewartbool DeviceInfo::GetMACAddress(int interface_index, ByteString *address) const {
534e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  const Info *info = GetInfo(interface_index);
535e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  if (!info) {
536e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov    return false;
537e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  }
538bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // |mac_address| from RTNL is not used for some devices, in which case it will
539bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // be empty here.
540bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (!info->mac_address.IsEmpty()) {
541bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    *address = info->mac_address;
542bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    return true;
543bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
544bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
545bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // Ask the kernel for the MAC address.
546bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  *address = GetMACAddressFromKernel(interface_index);
547bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  return !address->IsEmpty();
548bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain}
549bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain
550bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary MorainByteString DeviceInfo::GetMACAddressFromKernel(int interface_index) const {
551bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  ByteString mac_address;
552bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  mac_address.Clear();
553bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  // TODO(gmorain): Use ScopedSocketCloser instead.
554bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  const int fd = socket(PF_INET, SOCK_DGRAM, 0);
555bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (fd < 0) {
556bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    LOG(ERROR) << __func__ << ": Unable to open socket: " << fd;
557bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    return mac_address;
558bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
559bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  struct ifreq ifr;
560bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  memset(&ifr, 0, sizeof(ifr));
561bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  ifr.ifr_ifindex = interface_index;
562bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  int err = HANDLE_EINTR(ioctl(fd, SIOCGIFNAME, &ifr));
563bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (err < 0) {
564bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    LOG(ERROR) << __func__ << ": Unable to read ifname: " << errno;
565bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    close(fd);
566bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    return mac_address;
567bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
568bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  err = HANDLE_EINTR(ioctl(fd, SIOCGIFHWADDR, &ifr));
569bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  close(fd);
570bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  if (err < 0) {
571bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    LOG(ERROR) << __func__ << ": Unable to read MAC address: " << errno;
572bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain    return mac_address;
573bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  }
574bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  mac_address.Resize(IFHWADDRLEN);
575bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  memcpy(mac_address.GetData(), ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
576bf74a67a6dec2f438e6826a3f39c4e1100d1f016Gary Morain  return mac_address;
577e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov}
578e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov
5799a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartbool DeviceInfo::GetAddresses(int interface_index,
5809a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                              vector<AddressData> *addresses) const {
5819a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  const Info *info = GetInfo(interface_index);
5829a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!info) {
5839a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    return false;
5849a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
5859a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  *addresses = info->ip_addresses;
5869a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  return true;
5879a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
5889a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
5899a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartvoid DeviceInfo::FlushAddresses(int interface_index) const {
590fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__ << "(" << interface_index << ")";
5919a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  const Info *info = GetInfo(interface_index);
5929a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!info) {
5939a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    return;
5949a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
5959a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  const vector<AddressData> &addresses = info->ip_addresses;
5969a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  vector<AddressData>::const_iterator iter;
5979a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  for (iter = addresses.begin(); iter != addresses.end(); ++iter) {
5987355ce1937c504d836a303ac809bd436272212b3Paul Stewart    if (iter->address.family() == IPAddress::kFamilyIPv4 ||
5999a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart        (iter->scope == RT_SCOPE_UNIVERSE &&
6009a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart         (iter->flags & ~IFA_F_TEMPORARY) == 0)) {
6018c116a90d3a3536430b808b15e73275060918434Paul Stewart      SLOG(Device, 2) << __func__ << ": removing ip address "
6028c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << iter->address.ToString()
6038c116a90d3a3536430b808b15e73275060918434Paul Stewart                      << " from interface " << interface_index;
6049a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      rtnl_handler_->RemoveInterfaceAddress(interface_index, iter->address);
6059a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
6069a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
6079a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
6089a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
60905a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewartbool DeviceInfo::HasOtherAddress(
61005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    int interface_index, const IPAddress &this_address) const {
61105a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  SLOG(Device, 3) << __func__ << "(" << interface_index << ")";
61205a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  const Info *info = GetInfo(interface_index);
61305a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  if (!info) {
61405a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    return false;
61505a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  }
61605a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  const vector<AddressData> &addresses = info->ip_addresses;
61705a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  vector<AddressData>::const_iterator iter;
61805a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  bool has_other_address = false;
61905a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  bool has_this_address = false;
62005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  for (iter = addresses.begin(); iter != addresses.end(); ++iter) {
62105a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    if (iter->address.family() != this_address.family()) {
62205a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      continue;
62305a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    }
62405a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    if (iter->address.address().Equals(this_address.address())) {
62505a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_this_address = true;
62605a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    } else if (this_address.family() == IPAddress::kFamilyIPv4) {
62705a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_other_address = true;
62805a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    } else if ((iter->scope == RT_SCOPE_UNIVERSE &&
62905a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart                (iter->flags & IFA_F_TEMPORARY) == 0)) {
63005a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart      has_other_address = true;
63105a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart    }
63205a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  }
63305a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart  return has_other_address && !has_this_address;
63405a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart}
63505a42c23f1d37daa8689fc4240034e62ed89f8fcPaul Stewart
636e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkovbool DeviceInfo::GetFlags(int interface_index, unsigned int *flags) const {
637e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  const Info *info = GetInfo(interface_index);
638e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (!info) {
639e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    return false;
640e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  }
641e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  *flags = info->flags;
642e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return true;
643e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
644e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
6451ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartbool DeviceInfo::GetByteCounts(int interface_index,
6461ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                               uint64 *rx_bytes,
6471ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                               uint64 *tx_bytes) const {
6481ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  const Info *info = GetInfo(interface_index);
6491ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (!info) {
6501ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return false;
6511ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
6521ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  *rx_bytes = info->rx_bytes;
6531ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  *tx_bytes = info->tx_bytes;
6541ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  return true;
6551ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
6561ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
657ca6abd4635507fa5b8f4b8819a37819fb560c464Paul Stewartbool DeviceInfo::CreateTunnelInterface(string *interface_name) const {
658cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  int fd = HANDLE_EINTR(open(kTunDeviceName, O_RDWR));
659cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (fd < 0) {
660cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to open " << kTunDeviceName;
661cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
662cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
663cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  file_util::ScopedFD scoped_fd(&fd);
664cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
665cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  struct ifreq ifr;
666cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  memset(&ifr, 0, sizeof(ifr));
667cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
668cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (HANDLE_EINTR(ioctl(fd, TUNSETIFF, &ifr))) {
669cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to create tunnel interface";
670cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
671cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
672cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
673cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  if (HANDLE_EINTR(ioctl(fd, TUNSETPERSIST, 1))) {
674cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    PLOG(ERROR) << "failed to set tunnel interface to be persistent";
675cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart    return false;
676cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  }
677cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
678cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  *interface_name = string(ifr.ifr_name);
679cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
680cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  return true;
681cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart}
682cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
683ca6abd4635507fa5b8f4b8819a37819fb560c464Paul Stewartbool DeviceInfo::DeleteInterface(int interface_index) const {
684cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart  return rtnl_handler_->RemoveInterface(interface_index);
685cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart}
686cba0f7f604b28b1fe85a16b16b0731860dfff753Paul Stewart
687e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkovconst DeviceInfo::Info *DeviceInfo::GetInfo(int interface_index) const {
688e3e1cfaadc69ea67db55f11e55f404b11a70e354Darin Petkov  map<int, Info>::const_iterator iter = infos_.find(interface_index);
689e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (iter == infos_.end()) {
690e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    return NULL;
691e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  }
692e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  return &iter->second;
693e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov}
694e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov
695e6193c042652831cac90c3bbf2233877754b1eefDarin Petkovvoid DeviceInfo::RemoveInfo(int interface_index) {
696e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  map<int, Info>::iterator iter = infos_.find(interface_index);
697e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov  if (iter != infos_.end()) {
698fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << "Removing info for device index: " << interface_index;
699e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    if (iter->second.device.get()) {
700e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov      manager_->DeregisterDevice(iter->second.device);
701e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    }
702f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    indices_.erase(iter->second.name);
703e6193c042652831cac90c3bbf2233877754b1eefDarin Petkov    infos_.erase(iter);
704050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    delayed_devices_.erase(interface_index);
70547009f8d7a6fbc257a1bb1288a01405d034bd13fmukesh agrawal  } else {
706fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan    SLOG(Device, 2) << __func__ << ": Unknown device index: "
707fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan                    << interface_index;
708b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
7090af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
7100af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
7112aa9707f114ab8166f45df5726bf05278df2aef6Chris Masonevoid DeviceInfo::LinkMsgHandler(const RTNLMessage &msg) {
7129a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeLink);
7139a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (msg.mode() == RTNLMessage::kModeAdd) {
7142aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    AddLinkMsgHandler(msg);
7159a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  } else if (msg.mode() == RTNLMessage::kModeDelete) {
7162aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    DelLinkMsgHandler(msg);
7172aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone  } else {
7182aa9707f114ab8166f45df5726bf05278df2aef6Chris Masone    NOTREACHED();
719b50f0b9837c398b8edd5dc568eb01bdcff9a4d65Paul Stewart  }
7200af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}
7210af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart
7229a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewartvoid DeviceInfo::AddressMsgHandler(const RTNLMessage &msg) {
723fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan  SLOG(Device, 2) << __func__;
7249a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  DCHECK(msg.type() == RTNLMessage::kTypeAddress);
7259a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  int interface_index = msg.interface_index();
7269a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (!ContainsKey(infos_, interface_index)) {
7278c116a90d3a3536430b808b15e73275060918434Paul Stewart    SLOG(Device, 2) << "Got advance address information for unknown index "
7288c116a90d3a3536430b808b15e73275060918434Paul Stewart                    << interface_index;
7298c116a90d3a3536430b808b15e73275060918434Paul Stewart    infos_[interface_index].has_addresses_only = true;
7309a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
7319a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  const RTNLMessage::AddressStatus &status = msg.address_status();
7329a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  IPAddress address(msg.family(),
733682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan                    msg.HasAttribute(IFA_LOCAL) ?
734682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan                    msg.GetAttribute(IFA_LOCAL) : msg.GetAttribute(IFA_ADDRESS),
7359a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart                    status.prefix_len);
7369a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
737682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan  SLOG_IF(Device, 2, msg.HasAttribute(IFA_LOCAL))
738682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan      << "Found local address attribute for interface " << interface_index;
739682c5d4738cbdffc1ec88573a4a339840cc4fb25Ben Chan
7409a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  vector<AddressData> &address_list = infos_[interface_index].ip_addresses;
7419a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  vector<AddressData>::iterator iter;
7429a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  for (iter = address_list.begin(); iter != address_list.end(); ++iter) {
7439a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (address.Equals(iter->address)) {
7449a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      break;
7459a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
7469a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
7479a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  if (iter != address_list.end()) {
7489a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    if (msg.mode() == RTNLMessage::kModeDelete) {
749fad4a0b7e55dd82d3815ee96862b6e546727eb6eBen Chan      SLOG(Device, 2) << "Delete address for interface " << interface_index;
7509a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      address_list.erase(iter);
7519a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    } else {
7529a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      iter->flags = status.flags;
7539a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart      iter->scope = status.scope;
7549a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    }
7559a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  } else if (msg.mode() == RTNLMessage::kModeAdd) {
7569a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart    address_list.push_back(AddressData(address, status.flags, status.scope));
7578c116a90d3a3536430b808b15e73275060918434Paul Stewart    SLOG(Device, 2) << "Add address " << address.ToString()
7588c116a90d3a3536430b808b15e73275060918434Paul Stewart                    << " for interface " << interface_index;
7599a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart  }
7609a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart}
7619a908080fc2a72dbf06f995b878fc8a3693b725aPaul Stewart
762050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartvoid DeviceInfo::DelayDeviceCreation(int interface_index) {
763050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_.insert(interface_index);
764050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  delayed_devices_callback_.Reset(
765050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      Bind(&DeviceInfo::DelayedDeviceCreationTask, AsWeakPtr()));
766050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  dispatcher_->PostDelayedTask(delayed_devices_callback_.callback(),
767050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                               kDelayedDeviceCreationSeconds * 1000);
768050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart}
769050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
770050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart// Re-evaluate the technology type for each delayed device.
771050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewartvoid DeviceInfo::DelayedDeviceCreationTask() {
772050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  while (!delayed_devices_.empty()) {
773050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    set<int>::iterator it = delayed_devices_.begin();
774050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    int dev_index = *it;
775050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    delayed_devices_.erase(it);
776050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
777050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(ContainsKey(infos_, dev_index));
778050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(!GetDevice(dev_index));
779050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
780050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    const string &link_name = infos_[dev_index].name;
781050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    Technology::Identifier technology = GetDeviceTechnology(link_name);
782050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
783050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    if (technology == Technology::kCDCEthernet) {
784050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(INFO) << "In " << __func__ << ": device " << link_name
785050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                << " is now assumed to be regular Ethernet.";
786050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      technology = Technology::kEthernet;
787050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    } else if (technology != Technology::kCellular) {
788050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      LOG(WARNING) << "In " << __func__ << ": device " << link_name
789050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                   << " is unexpected technology "
790050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                   << Technology::NameFromIdentifier(technology);
791050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
792050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    string address =
793050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart        StringToLowerASCII(infos_[dev_index].mac_address.HexEncode());
794050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DCHECK(!address.empty());
795050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
796050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    DeviceRefPtr device = CreateDevice(link_name, address, dev_index,
797050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart                                       technology);
798050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    if (device) {
799050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart      RegisterDevice(device);
800050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart    }
801050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart  }
802050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart}
803050cfc068fda2bd77df2ba08f7b2897bf0e0a6e0Paul Stewart
8041ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartvoid DeviceInfo::RetrieveLinkStatistics(int interface_index,
8051ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                                        const RTNLMessage &msg) {
8061ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (!msg.HasAttribute(IFLA_STATS64)) {
8071ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return;
8081ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
8091ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  ByteString stats_bytes(msg.GetAttribute(IFLA_STATS64));
8101ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  struct rtnl_link_stats64 stats;
8111ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  if (stats_bytes.GetLength() < sizeof(stats)) {
8121ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    LOG(WARNING) << "Link statistics size is too small: "
8131ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                 << stats_bytes.GetLength() << " < " << sizeof(stats);
8141ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart    return;
8151ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  }
8161ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
8171ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  memcpy(&stats, stats_bytes.GetConstData(), sizeof(stats));
8181ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  SLOG(Device, 2) << "Link statistics for "
8191ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                  << " interface index " << interface_index << ": "
8201ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                  << "receive: " << stats.rx_bytes << "; "
8211ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                  << "transmit: " << stats.tx_bytes << ".";
8221ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  infos_[interface_index].rx_bytes = stats.rx_bytes;
8231ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  infos_[interface_index].tx_bytes = stats.tx_bytes;
8241ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
8251ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
8261ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewartvoid DeviceInfo::RequestLinkStatistics() {
8271ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
8281ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart  dispatcher_->PostDelayedTask(request_link_statistics_callback_.callback(),
8291ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart                               kRequestLinkStatisticsIntervalSeconds * 1000);
8301ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart}
8311ac4e84148e03752d99aecea4f743abb094f28b0Paul Stewart
8320af98bf87e8fc3cf29293f62d7f3b73cd9adb571Paul Stewart}  // namespace shill
833