device_info.cc revision 1ff67a70eb6dea94ba8a6a836add9810536bec31
1fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu// Copyright 2014 The Chromium OS Authors. All rights reserved.
2fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu// Use of this source code is governed by a BSD-style license that can be
3fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu// found in the LICENSE file.
4fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
5fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include "apmanager/device_info.h"
6fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
7fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <linux/rtnetlink.h>
8fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
9fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <string>
10fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
11fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <base/bind.h>
12fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <base/files/file_util.h>
13fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <base/logging.h>
14fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/netlink_attribute.h>
15fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/netlink_manager.h>
16fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/nl80211_message.h>
17fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/rtnl_handler.h>
18fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/rtnl_listener.h>
19fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/rtnl_message.h>
20fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/sockets.h>
21fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
22fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include "apmanager/manager.h"
23fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
24fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing base::Bind;
25fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::ByteString;
26fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::NetlinkManager;
27fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::NetlinkMessage;
28fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::Nl80211Message;
29fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::RTNLHandler;
30fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::RTNLMessage;
31fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::RTNLListener;
32fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing std::map;
33fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing std::string;
34fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
35fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiunamespace apmanager {
36fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
37fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuconst char DeviceInfo::kDeviceInfoRoot[] = "/sys/class/net";
38fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuconst char DeviceInfo::kInterfaceUevent[] = "uevent";
39fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuconst char DeviceInfo::kInterfaceUeventWifiSignature[] = "DEVTYPE=wlan\n";
40fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
41fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter QiuDeviceInfo::DeviceInfo(Manager* manager)
42fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    : link_callback_(Bind(&DeviceInfo::LinkMsgHandler, Unretained(this))),
43fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      device_info_root_(kDeviceInfoRoot),
44fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      manager_(manager),
45fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      netlink_manager_(NetlinkManager::GetInstance()),
46fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      rtnl_handler_(RTNLHandler::GetInstance()),
47fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      sockets_(new shill::Sockets()) {
48fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
49fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
50fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter QiuDeviceInfo::~DeviceInfo() {}
51fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
52fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::Start() {
53fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Start netlink manager.
54fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->Init();
55fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  uint16_t nl80211_family_id = netlink_manager_->GetFamily(
56fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Nl80211Message::kMessageTypeString,
57fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&Nl80211Message::CreateMessage));
58fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (nl80211_family_id == NetlinkMessage::kIllegalMessageType) {
59fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(FATAL) << "Didn't get a legal message type for 'nl80211' messages.";
60fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
61fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  Nl80211Message::SetMessageType(nl80211_family_id);
62fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->Start();
63fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
64fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Start enumerating WiFi devices (PHYs).
65fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  EnumerateDevices();
66fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
67fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Start RTNL for monitoring network interfaces.
68fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  rtnl_handler_->Start(sockets_.get());
69fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  link_listener_.reset(
70fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      new RTNLListener(RTNLHandler::kRequestLink, link_callback_));
711ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  // Request link infos.
721ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
73fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
74fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
75fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::Stop() {
76fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  link_listener_.reset();
77fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
78fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
79fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::EnumerateDevices() {
80fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  shill::GetWiphyMessage get_wiphy;
81fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  get_wiphy.attributes()->SetFlagAttributeValue(NL80211_ATTR_SPLIT_WIPHY_DUMP,
82fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                true);
83fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  get_wiphy.AddFlag(NLM_F_DUMP);
84fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->SendNl80211Message(
85fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      &get_wiphy,
86fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&DeviceInfo::OnWiFiPhyInfoReceived, AsWeakPtr()),
87fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnAckDoNothing),
88fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnNetlinkMessageError));
89fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
90fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
91fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::OnWiFiPhyInfoReceived(const shill::Nl80211Message& msg) {
92fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Verify NL80211_CMD_NEW_WIPHY.
93fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.command() != shill::NewWiphyMessage::kCommand) {
94fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Received unexpected command:"
95fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << msg.command();
96fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
97fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
98fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
991ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  string device_name;
1001ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  if (!msg.const_attributes()->GetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
1011ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu                                                       &device_name)) {
1021ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME";
1031ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    return;
1041ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  }
1051ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu
1061ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  if (GetDevice(device_name)) {
1071ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    LOG(INFO) << "Device " << device_name << " already enumerated.";
1081ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    return;
1091ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  }
1101ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu
1111ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  scoped_refptr<Device> device = new Device(device_name);
1121ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  device->ParseWiphyCapability(msg);
113fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
114fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Register device
115fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  RegisterDevice(device);
116fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
117fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
118fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::LinkMsgHandler(const RTNLMessage& msg) {
119fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  DCHECK(msg.type() == RTNLMessage::kTypeLink);
120fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
121fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Get interface name.
122fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.HasAttribute(IFLA_IFNAME)) {
123fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Link event message does not have IFLA_IFNAME!";
124fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
125fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
126fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  ByteString b(msg.GetAttribute(IFLA_IFNAME));
127fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  string iface_name(reinterpret_cast<const char*>(b.GetConstData()));
128fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
129fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  int dev_index = msg.interface_index();
130fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.mode() == RTNLMessage::kModeAdd) {
131fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    AddLinkMsgHandler(iface_name, dev_index);
132fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  } else if (msg.mode() == RTNLMessage::kModeDelete) {
133fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    DelLinkMsgHandler(iface_name, dev_index);
134fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  } else {
135fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    NOTREACHED();
136fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
137fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
138fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
139fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::AddLinkMsgHandler(const string& iface_name, int iface_index) {
140fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Ignore non-wifi interfaces.
141fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!IsWifiInterface(iface_name)) {
142fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "Ignore link event for non-wifi interface: " << iface_name;
143fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
144fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
145fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
146fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Return if interface already existed. Could receive multiple add link event
147fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // for a single interface.
148fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (interface_infos_.find(iface_index) != interface_infos_.end()) {
149fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "AddLinkMsgHandler: interface " << iface_name
150fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu              << " is already added";
151fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
152fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
153fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
154fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Add interface.
155fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  Device::WiFiInterface wifi_interface;
156fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  wifi_interface.iface_name = iface_name;
157fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  wifi_interface.iface_index = iface_index;
158fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  interface_infos_[iface_index] = wifi_interface;
159fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
160fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Get interface info.
161fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  GetWiFiInterfaceInfo(iface_index);
162fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
163fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
164fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::DelLinkMsgHandler(const string& iface_name, int iface_index) {
165fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  LOG(INFO) << "DelLinkMsgHandler iface_name: " << iface_name
166fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu            << "iface_index: " << iface_index;
167fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<uint32_t, Device::WiFiInterface>::iterator iter =
168fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      interface_infos_.find(iface_index);
169fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter != interface_infos_.end()) {
170fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    // Deregister interface from the Device.
171fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    scoped_refptr<Device> device = GetDevice(iter->second.device_name);
172fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    if (device) {
173fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      device->DeregisterInterface(iter->second);
174fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    }
175fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    interface_infos_.erase(iter);
176fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
177fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
178fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
179fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiubool DeviceInfo::IsWifiInterface(const string& iface_name) {
180fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  string contents;
181fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!GetDeviceInfoContents(iface_name, kInterfaceUevent, &contents)) {
182fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "Interface " << iface_name << " has no uevent file";
183fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return false;
184fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
185fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
186fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (contents.find(kInterfaceUeventWifiSignature) == string::npos) {
187fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "Interface " << iface_name << " is not a WiFi interface";
188fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return false;
189fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
190fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
191fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  return true;
192fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
193fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
194fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiubool DeviceInfo::GetDeviceInfoContents(const string& iface_name,
195fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                       const string& path_name,
196fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                       string* contents_out) {
197fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  return base::ReadFileToString(
198fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      device_info_root_.Append(iface_name).Append(path_name),
199fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      contents_out);
200fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
201fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
202fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::GetWiFiInterfaceInfo(int interface_index) {
203fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  shill::GetInterfaceMessage msg;
204fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
205fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                              interface_index)) {
206fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Unable to set interface index attribute for "
207fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                  "GetInterface message.  Interface type cannot be "
208fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                  "determined!";
209fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
210fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
211fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
212fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->SendNl80211Message(
213fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      &msg,
214fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&DeviceInfo::OnWiFiInterfaceInfoReceived, AsWeakPtr()),
215fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnAckDoNothing),
216fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnNetlinkMessageError));
217fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
218fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
219fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::OnWiFiInterfaceInfoReceived(const shill::Nl80211Message& msg) {
220fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.command() != NL80211_CMD_NEW_INTERFACE) {
221fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Message is not a new interface response";
222fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
223fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
224fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
225fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  uint32_t interface_index;
226fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFINDEX,
227fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                    &interface_index)) {
228fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Message contains no interface index";
229fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
230fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
231fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  uint32_t interface_type;
232fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFTYPE,
233fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                    &interface_type)) {
234fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Message contains no interface type";
235fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
236fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
237fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
238fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<uint32_t, Device::WiFiInterface>::iterator iter =
239fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      interface_infos_.find(interface_index);
240fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter == interface_infos_.end()) {
241fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Receive WiFi interface info for non-exist interface: "
242fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << interface_index;
243fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
244fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
245fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  iter->second.iface_type = interface_type;
246fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
247fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Request PHY info, to know which Device to register this interface to.
248fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  GetWiFiInterfacePhyInfo(interface_index);
249fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
250fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
251fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::GetWiFiInterfacePhyInfo(uint32_t iface_index) {
252fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  shill::GetWiphyMessage get_wiphy;
253fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
254fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                               iface_index);
255fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->SendNl80211Message(
256fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      &get_wiphy,
257fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&DeviceInfo::OnWiFiInterfacePhyInfoReceived,
258fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu           AsWeakPtr(),
259fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu           iface_index),
260fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnAckDoNothing),
261fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnNetlinkMessageError));
262fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
263fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
264fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::OnWiFiInterfacePhyInfoReceived(
265fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    uint32_t iface_index, const shill::Nl80211Message& msg) {
266fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Verify NL80211_CMD_NEW_WIPHY.
267fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.command() != shill::NewWiphyMessage::kCommand) {
268fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Received unexpected command:"
269fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << msg.command();
270fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
271fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
272fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
273fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<uint32_t, Device::WiFiInterface>::iterator iter =
274fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      interface_infos_.find(iface_index);
275fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter == interface_infos_.end()) {
276fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    // Interface is gone by the time we received its PHY info.
277fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Interface [" << iface_index
278fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << "] is deleted when PHY info is received";
279fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
280fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
281fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
282fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  string device_name;
283fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.const_attributes()->GetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
284fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                       &device_name)) {
285fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME";
286fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
287fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
288fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
289fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  scoped_refptr<Device> device = GetDevice(device_name);
2901ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  // Create device if it is not enumerated yet.
291fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!device) {
2921ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    device = new Device(device_name);
2931ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    device->ParseWiphyCapability(msg);
2941ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu
2951ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    // Register device
2961ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    RegisterDevice(device);
297fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
298fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  iter->second.device_name = device_name;
299fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
300fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  device->RegisterInterface(iter->second);
301fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
302fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
303fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::RegisterDevice(scoped_refptr<Device> device) {
304fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!device) {
305fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
306fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
307fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  devices_[device->GetDeviceName()] = device;
308fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Register device with manager.
309fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  manager_->RegisterDevice(device);
310fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
311fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
312fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuscoped_refptr<Device> DeviceInfo::GetDevice(const string& device_name) {
313fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<string, scoped_refptr<Device>>::iterator iter =
314fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      devices_.find(device_name);
315fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter == devices_.end()) {
316fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return nullptr;
317fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
318fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  return iter->second;
319fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
320fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
321fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}  // namespace apmanager
322