blob: 4162fd4d0085e1e91c306a880414bb93f21558c8 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHILL_DEVICE_INFO_
#define SHILL_DEVICE_INFO_
#include <map>
#include <set>
#include <string>
#include <vector>
#include <base/callback.h>
#include <base/cancelable_callback.h>
#include <base/files/file_path.h>
#include <base/memory/ref_counted.h>
#include <base/memory/scoped_ptr.h>
#include <base/memory/weak_ptr.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "shill/byte_string.h"
#include "shill/device.h"
#include "shill/ip_address.h"
#include "shill/rtnl_listener.h"
#include "shill/technology.h"
namespace shill {
class Manager;
class Metrics;
class NetlinkManager;
class Nl80211Message;
class RoutingTable;
class RTNLHandler;
class RTNLMessage;
class Sockets;
class DeviceInfo : public base::SupportsWeakPtr<DeviceInfo> {
public:
struct AddressData {
AddressData()
: address(IPAddress::kFamilyUnknown), flags(0), scope(0) {}
AddressData(const IPAddress &address_in,
unsigned char flags_in,
unsigned char scope_in)
: address(address_in), flags(flags_in), scope(scope_in) {}
IPAddress address;
unsigned char flags;
unsigned char scope;
};
// Device name prefix for modem pseudo devices used in testing.
static const char kModemPseudoDeviceNamePrefix[];
// Device name prefix for virtual ethernet devices used in testing.
static const char kEthernetPseudoDeviceNamePrefix[];
// Time interval for polling for link statistics.
static const int kRequestLinkStatisticsIntervalMilliseconds;
DeviceInfo(ControlInterface *control_interface,
EventDispatcher *dispatcher,
Metrics *metrics,
Manager *manager);
virtual ~DeviceInfo();
void AddDeviceToBlackList(const std::string &device_name);
virtual bool IsDeviceBlackListed(const std::string &device_name);
void Start();
void Stop();
std::vector<std::string> GetUninitializedTechnologies() const;
// Adds |device| to this DeviceInfo instance so that we can handle its link
// messages, and registers it with the manager.
virtual void RegisterDevice(const DeviceRefPtr &device);
// Remove |device| from this DeviceInfo. This function should only
// be called for cellular devices because the lifetime of the
// cellular devices is controlled by the Modem object and its
// communication to modem manager, rather than by RTNL messages.
virtual void DeregisterDevice(const DeviceRefPtr &device);
virtual DeviceRefPtr GetDevice(int interface_index) const;
virtual bool GetMACAddress(int interface_index, ByteString *address) const;
// Queries the kernel for a MAC address for |interface_index|. Returns an
// empty ByteString on failure.
virtual ByteString GetMACAddressFromKernel(int interface_index) const;
// Queries the kernel for the MAC address of |peer| on |interface_index|.
// Returns true and populates |mac_address| on success, otherwise returns
// false.
virtual bool GetMACAddressOfPeer(int interface_index,
const IPAddress &peer,
ByteString *mac_address) const;
virtual bool GetFlags(int interface_index, unsigned int *flags) const;
virtual bool GetByteCounts(int interface_index,
uint64 *rx_bytes, uint64 *tx_bytes) const;
virtual bool GetAddresses(int interface_index,
std::vector<AddressData> *addresses) const;
// Flush all addresses associated with |interface_index|.
virtual void FlushAddresses(int interface_index) const;
// Returns whether this interface does not have |this_address|
// but has another non-temporary address of the same family.
virtual bool HasOtherAddress(
int interface_index, const IPAddress &this_address) const;
// Get the preferred globally scoped IPv6 address for |interface_index|.
// This method returns true and sets |address| if a primary IPv6 address
// exists. Otherwise it returns false and leaves |address| unmodified.
virtual bool GetPrimaryIPv6Address(int interface_index, IPAddress *address);
// Returns true if any of the addresses on |interface_index| are on the
// same network prefix as |address|.
virtual bool HasDirectConnectivityTo(
int interface_index, const IPAddress &address) const;
virtual bool CreateTunnelInterface(std::string *interface_name) const;
virtual bool DeleteInterface(int interface_index) const;
// Returns the interface index for |interface_name| or -1 if unknown.
virtual int GetIndex(const std::string &interface_name) const;
private:
friend class DeviceInfoDelayedCreationTest;
friend class DeviceInfoTechnologyTest;
friend class DeviceInfoTest;
FRIEND_TEST(CellularTest, StartLinked);
FRIEND_TEST(DeviceInfoTest, CreateDeviceWiMax);
FRIEND_TEST(DeviceInfoTest, GetUninitializedTechnologies);
FRIEND_TEST(DeviceInfoTest, HasSubdir); // For HasSubdir.
FRIEND_TEST(DeviceInfoTest, IPv6AddressChanged); // For infos_.
FRIEND_TEST(DeviceInfoTest, RequestLinkStatistics);
FRIEND_TEST(DeviceInfoTest, StartStop);
struct Info {
Info()
: flags(0),
rx_bytes(0),
tx_bytes(0),
has_addresses_only(false),
technology(Technology::kUnknown)
{}
DeviceRefPtr device;
std::string name;
ByteString mac_address;
std::vector<AddressData> ip_addresses;
unsigned int flags;
uint64 rx_bytes;
uint64 tx_bytes;
// This flag indicates that link information has not been retrieved yet;
// only the ip_addresses field is valid.
bool has_addresses_only;
Technology::Identifier technology;
};
// Root of the kernel sysfs directory holding network device info.
static const char kDeviceInfoRoot[];
// Name of the "cdc_ether" driver. This driver is not included in the
// kModemDrivers list because we need to do additional checking.
static const char kDriverCdcEther[];
// Name of the "cdc_ncm" driver. This driver is not included in the
// kModemDrivers list because we need to do additional checking.
static const char kDriverCdcNcm[];
// Name of the GDM WiMAX driver.
static const char kDriverGdmWiMax[];
// Name of the virtio network driver.
static const char kDriverVirtioNet[];
// Sysfs path to a device uevent file.
static const char kInterfaceUevent[];
// Content of a device uevent file that indicates it is a wifi device.
static const char kInterfaceUeventWifiSignature[];
// Sysfs path to a device via its interface name.
static const char kInterfaceDevice[];
// Sysfs path to the driver of a device via its interface name.
static const char kInterfaceDriver[];
// Sysfs path to the file that is used to determine if this is tun device.
static const char kInterfaceTunFlags[];
// Sysfs path to the file that is used to determine if a wifi device is
// operating in monitor mode.
static const char kInterfaceType[];
// Modem drivers that we support.
static const char *kModemDrivers[];
// Path to the tun device.
static const char kTunDeviceName[];
// Time to wait before registering devices which need extra time to detect.
static const int kDelayedDeviceCreationSeconds;
// Create a Device object for the interface named |linkname|, with a
// string-form MAC address |address|, whose kernel interface index
// is |interface_index| and detected technology is |technology|.
virtual DeviceRefPtr CreateDevice(const std::string &link_name,
const std::string &address,
int interface_index,
Technology::Identifier technology);
// Return the FilePath for a given |path_name| in the device sysinfo for
// a specific interface |iface_name|.
base::FilePath GetDeviceInfoPath(const std::string &iface_name,
const std::string &path_name);
// Return the contents of the device info file |path_name| for interface
// |iface_name| in output parameter |contents_out|. Returns true if file
// read succeeded, false otherwise.
bool GetDeviceInfoContents(const std::string &iface_name,
const std::string &path_name,
std::string *contents_out);
// Return the filepath for the target of the device info symbolic link
// |path_name| for interface |iface_name| in output parameter |path_out|.
// Returns true if symbolic link read succeeded, false otherwise.
bool GetDeviceInfoSymbolicLink(const std::string &iface_name,
const std::string &path_name,
base::FilePath *path_out);
// Classify the device named |iface_name|, and return an identifier
// indicating its type.
virtual Technology::Identifier GetDeviceTechnology(
const std::string &iface_name);
// Checks the device specified by |iface_name| to see if it's a modem device.
// This method assumes that |iface_name| has already been determined to be
// using the cdc_ether / cdc_ncm driver.
bool IsCdcEthernetModemDevice(const std::string &iface_name);
// Returns true if |base_dir| has a subdirectory named |subdir|.
// |subdir| can be an immediate subdirectory of |base_dir| or can be
// several levels deep.
static bool HasSubdir(const base::FilePath &base_dir,
const base::FilePath &subdir);
void AddLinkMsgHandler(const RTNLMessage &msg);
void DelLinkMsgHandler(const RTNLMessage &msg);
void LinkMsgHandler(const RTNLMessage &msg);
void AddressMsgHandler(const RTNLMessage &msg);
const Info *GetInfo(int interface_index) const;
void RemoveInfo(int interface_index);
void DelayDeviceCreation(int interface_index);
void DelayedDeviceCreationTask();
void RetrieveLinkStatistics(int interface_index, const RTNLMessage &msg);
void RequestLinkStatistics();
// Use nl80211 to get information on |interface_index|.
void GetWiFiInterfaceInfo(int interface_index);
void OnWiFiInterfaceInfoReceived(const Nl80211Message &message);
void set_sockets(Sockets* sockets) { sockets_.reset(sockets); }
ControlInterface *control_interface_;
EventDispatcher *dispatcher_;
Metrics *metrics_;
Manager *manager_;
std::map<int, Info> infos_; // Maps interface index to Info.
std::map<std::string, int> indices_; // Maps interface name to index.
base::Callback<void(const RTNLMessage &)> link_callback_;
base::Callback<void(const RTNLMessage &)> address_callback_;
scoped_ptr<RTNLListener> link_listener_;
scoped_ptr<RTNLListener> address_listener_;
std::set<std::string> black_list_;
base::FilePath device_info_root_;
// Keep track of devices that require a delayed call to CreateDevice().
base::CancelableClosure delayed_devices_callback_;
std::set<int> delayed_devices_;
// Maintain a callback for the periodic link statistics poll task.
base::CancelableClosure request_link_statistics_callback_;
// Cache copy of singleton pointers.
RoutingTable *routing_table_;
RTNLHandler *rtnl_handler_;
NetlinkManager *netlink_manager_;
// A member of the class so that a mock can be injected for testing.
scoped_ptr<Sockets> sockets_;
DISALLOW_COPY_AND_ASSIGN(DeviceInfo);
};
} // namespace shill
#endif // SHILL_DEVICE_INFO_