1326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu//
2326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// Copyright (C) 2014 The Android Open Source Project
3326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu//
4326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// you may not use this file except in compliance with the License.
6326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// You may obtain a copy of the License at
7326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu//
8326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu//
10326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// Unless required by applicable law or agreed to in writing, software
11326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// See the License for the specific language governing permissions and
14326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu// limitations under the License.
15326b6cfba5ab73c9e41a7585d1bc95871631122aPeter Qiu//
16fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
17fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include "apmanager/device_info.h"
18fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
19fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <linux/rtnetlink.h>
20fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
21fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <string>
22fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
23fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <base/bind.h>
24fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <base/files/file_util.h>
25fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <base/logging.h>
2674cfdc9a3fb1a1052512971b9c48f5fb5fd9e5fcNathan Bullock#include <shill/net/ndisc.h>
27fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/netlink_attribute.h>
28fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/netlink_manager.h>
29fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/nl80211_message.h>
30fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/rtnl_handler.h>
31fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/rtnl_listener.h>
32fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include <shill/net/rtnl_message.h>
33fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
34f933540bb968efa2744ee48b40ab713ccd358d51Peter Qiu#include "apmanager/control_interface.h"
35fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu#include "apmanager/manager.h"
36fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
37fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing base::Bind;
38fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::ByteString;
39fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::NetlinkManager;
40fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::NetlinkMessage;
41fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::Nl80211Message;
42fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::RTNLHandler;
43fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::RTNLMessage;
44fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing shill::RTNLListener;
45fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing std::map;
46fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuusing std::string;
47fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
48fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiunamespace apmanager {
49fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
50fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuconst char DeviceInfo::kDeviceInfoRoot[] = "/sys/class/net";
51fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuconst char DeviceInfo::kInterfaceUevent[] = "uevent";
52fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuconst char DeviceInfo::kInterfaceUeventWifiSignature[] = "DEVTYPE=wlan\n";
53fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
54fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter QiuDeviceInfo::DeviceInfo(Manager* manager)
55fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    : link_callback_(Bind(&DeviceInfo::LinkMsgHandler, Unretained(this))),
56fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      device_info_root_(kDeviceInfoRoot),
57fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      manager_(manager),
58fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      netlink_manager_(NetlinkManager::GetInstance()),
59f933540bb968efa2744ee48b40ab713ccd358d51Peter Qiu      rtnl_handler_(RTNLHandler::GetInstance()),
60f933540bb968efa2744ee48b40ab713ccd358d51Peter Qiu      device_identifier_(0) {
61fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
62fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
63fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter QiuDeviceInfo::~DeviceInfo() {}
64fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
65fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::Start() {
66fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Start netlink manager.
67fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->Init();
68fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  uint16_t nl80211_family_id = netlink_manager_->GetFamily(
69fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Nl80211Message::kMessageTypeString,
70fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&Nl80211Message::CreateMessage));
71fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (nl80211_family_id == NetlinkMessage::kIllegalMessageType) {
72fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(FATAL) << "Didn't get a legal message type for 'nl80211' messages.";
73fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
74fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  Nl80211Message::SetMessageType(nl80211_family_id);
75fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->Start();
76fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
77fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Start enumerating WiFi devices (PHYs).
78fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  EnumerateDevices();
79fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
80fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Start RTNL for monitoring network interfaces.
8174cfdc9a3fb1a1052512971b9c48f5fb5fd9e5fcNathan Bullock  rtnl_handler_->Start(RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
8274cfdc9a3fb1a1052512971b9c48f5fb5fd9e5fcNathan Bullock                       RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
8374cfdc9a3fb1a1052512971b9c48f5fb5fd9e5fcNathan Bullock                       RTMGRP_ND_USEROPT);
84fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  link_listener_.reset(
85fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      new RTNLListener(RTNLHandler::kRequestLink, link_callback_));
861ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  // Request link infos.
871ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
88fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
89fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
90fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::Stop() {
91fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  link_listener_.reset();
92fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
93fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
94fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::EnumerateDevices() {
95fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  shill::GetWiphyMessage get_wiphy;
96fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  get_wiphy.attributes()->SetFlagAttributeValue(NL80211_ATTR_SPLIT_WIPHY_DUMP,
97fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                true);
98fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  get_wiphy.AddFlag(NLM_F_DUMP);
99fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->SendNl80211Message(
100fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      &get_wiphy,
101fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&DeviceInfo::OnWiFiPhyInfoReceived, AsWeakPtr()),
102fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnAckDoNothing),
103fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnNetlinkMessageError));
104fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
105fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
106fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::OnWiFiPhyInfoReceived(const shill::Nl80211Message& msg) {
107fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Verify NL80211_CMD_NEW_WIPHY.
108fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.command() != shill::NewWiphyMessage::kCommand) {
109fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Received unexpected command:"
110fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << msg.command();
111fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
112fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
113fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
1141ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  string device_name;
1151ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  if (!msg.const_attributes()->GetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
1161ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu                                                       &device_name)) {
1171ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME";
1181ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    return;
1191ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  }
1201ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu
1211ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  if (GetDevice(device_name)) {
1221ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    LOG(INFO) << "Device " << device_name << " already enumerated.";
1231ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    return;
1241ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  }
1251ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu
126f933540bb968efa2744ee48b40ab713ccd358d51Peter Qiu  scoped_refptr<Device> device =
127f933540bb968efa2744ee48b40ab713ccd358d51Peter Qiu      new Device(manager_, device_name, device_identifier_++);
1281ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  device->ParseWiphyCapability(msg);
129fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
130fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Register device
131fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  RegisterDevice(device);
132fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
133fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
134fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::LinkMsgHandler(const RTNLMessage& msg) {
135fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  DCHECK(msg.type() == RTNLMessage::kTypeLink);
136fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
137fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Get interface name.
138fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.HasAttribute(IFLA_IFNAME)) {
139fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Link event message does not have IFLA_IFNAME!";
140fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
141fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
142fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  ByteString b(msg.GetAttribute(IFLA_IFNAME));
143fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  string iface_name(reinterpret_cast<const char*>(b.GetConstData()));
144fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
145fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  int dev_index = msg.interface_index();
146fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.mode() == RTNLMessage::kModeAdd) {
147fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    AddLinkMsgHandler(iface_name, dev_index);
148fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  } else if (msg.mode() == RTNLMessage::kModeDelete) {
149fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    DelLinkMsgHandler(iface_name, dev_index);
150fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  } else {
151fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    NOTREACHED();
152fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
153fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
154fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
155fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::AddLinkMsgHandler(const string& iface_name, int iface_index) {
156fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Ignore non-wifi interfaces.
157fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!IsWifiInterface(iface_name)) {
158fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "Ignore link event for non-wifi interface: " << iface_name;
159fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
160fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
161fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
162fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Return if interface already existed. Could receive multiple add link event
163fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // for a single interface.
164fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (interface_infos_.find(iface_index) != interface_infos_.end()) {
165fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "AddLinkMsgHandler: interface " << iface_name
166fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu              << " is already added";
167fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
168fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
169fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
170fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Add interface.
171fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  Device::WiFiInterface wifi_interface;
172fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  wifi_interface.iface_name = iface_name;
173fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  wifi_interface.iface_index = iface_index;
174fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  interface_infos_[iface_index] = wifi_interface;
175fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
176fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Get interface info.
177fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  GetWiFiInterfaceInfo(iface_index);
178fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
179fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
180fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::DelLinkMsgHandler(const string& iface_name, int iface_index) {
181fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  LOG(INFO) << "DelLinkMsgHandler iface_name: " << iface_name
182fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu            << "iface_index: " << iface_index;
183fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<uint32_t, Device::WiFiInterface>::iterator iter =
184fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      interface_infos_.find(iface_index);
185fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter != interface_infos_.end()) {
186fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    // Deregister interface from the Device.
187fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    scoped_refptr<Device> device = GetDevice(iter->second.device_name);
188fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    if (device) {
189fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      device->DeregisterInterface(iter->second);
190fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    }
191fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    interface_infos_.erase(iter);
192fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
193fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
194fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
195fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiubool DeviceInfo::IsWifiInterface(const string& iface_name) {
196fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  string contents;
197fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!GetDeviceInfoContents(iface_name, kInterfaceUevent, &contents)) {
198fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "Interface " << iface_name << " has no uevent file";
199fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return false;
200fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
201fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
202fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (contents.find(kInterfaceUeventWifiSignature) == string::npos) {
203fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(INFO) << "Interface " << iface_name << " is not a WiFi interface";
204fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return false;
205fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
206fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
207fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  return true;
208fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
209fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
210fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiubool DeviceInfo::GetDeviceInfoContents(const string& iface_name,
211fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                       const string& path_name,
212fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                       string* contents_out) {
213fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  return base::ReadFileToString(
214fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      device_info_root_.Append(iface_name).Append(path_name),
215fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      contents_out);
216fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
217fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
218fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::GetWiFiInterfaceInfo(int interface_index) {
219fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  shill::GetInterfaceMessage msg;
220fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
221fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                              interface_index)) {
222fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Unable to set interface index attribute for "
223fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                  "GetInterface message.  Interface type cannot be "
224fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                  "determined!";
225fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
226fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
227fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
228fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->SendNl80211Message(
229fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      &msg,
230fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&DeviceInfo::OnWiFiInterfaceInfoReceived, AsWeakPtr()),
231fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnAckDoNothing),
232fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnNetlinkMessageError));
233fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
234fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
235fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::OnWiFiInterfaceInfoReceived(const shill::Nl80211Message& msg) {
236fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.command() != NL80211_CMD_NEW_INTERFACE) {
237fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Message is not a new interface response";
238fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
239fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
240fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
241fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  uint32_t interface_index;
242fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFINDEX,
243fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                    &interface_index)) {
244fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Message contains no interface index";
245fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
246fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
247fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  uint32_t interface_type;
248fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFTYPE,
249fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                    &interface_type)) {
250fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Message contains no interface type";
251fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
252fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
253fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
254fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<uint32_t, Device::WiFiInterface>::iterator iter =
255fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      interface_infos_.find(interface_index);
256fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter == interface_infos_.end()) {
257fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Receive WiFi interface info for non-exist interface: "
258fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << interface_index;
259fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
260fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
261fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  iter->second.iface_type = interface_type;
262fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
263fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Request PHY info, to know which Device to register this interface to.
264fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  GetWiFiInterfacePhyInfo(interface_index);
265fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
266fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
267fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::GetWiFiInterfacePhyInfo(uint32_t iface_index) {
268fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  shill::GetWiphyMessage get_wiphy;
269fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
270fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                               iface_index);
271fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  netlink_manager_->SendNl80211Message(
272fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      &get_wiphy,
273fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&DeviceInfo::OnWiFiInterfacePhyInfoReceived,
274fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu           AsWeakPtr(),
275fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu           iface_index),
276fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnAckDoNothing),
277fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      Bind(&NetlinkManager::OnNetlinkMessageError));
278fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
279fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
280fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::OnWiFiInterfacePhyInfoReceived(
281fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    uint32_t iface_index, const shill::Nl80211Message& msg) {
282fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Verify NL80211_CMD_NEW_WIPHY.
283fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (msg.command() != shill::NewWiphyMessage::kCommand) {
284fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Received unexpected command:"
285fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << msg.command();
286fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
287fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
288fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
289fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<uint32_t, Device::WiFiInterface>::iterator iter =
290fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      interface_infos_.find(iface_index);
291fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter == interface_infos_.end()) {
292fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    // Interface is gone by the time we received its PHY info.
293fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "Interface [" << iface_index
294fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu               << "] is deleted when PHY info is received";
295fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
296fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
297fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
298fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  string device_name;
299fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!msg.const_attributes()->GetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
300fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu                                                       &device_name)) {
301fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME";
302fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
303fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
304fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
305fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  scoped_refptr<Device> device = GetDevice(device_name);
3061ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu  // Create device if it is not enumerated yet.
307fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!device) {
308f933540bb968efa2744ee48b40ab713ccd358d51Peter Qiu    device =
309f933540bb968efa2744ee48b40ab713ccd358d51Peter Qiu        new Device(manager_, device_name, device_identifier_++);
3101ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    device->ParseWiphyCapability(msg);
3111ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu
3121ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    // Register device
3131ff67a70eb6dea94ba8a6a836add9810536bec31Peter Qiu    RegisterDevice(device);
314fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
315fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  iter->second.device_name = device_name;
316fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
317fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  device->RegisterInterface(iter->second);
318fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
319fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
320fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuvoid DeviceInfo::RegisterDevice(scoped_refptr<Device> device) {
321fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (!device) {
322fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return;
323fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
324fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  devices_[device->GetDeviceName()] = device;
325fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  // Register device with manager.
326fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  manager_->RegisterDevice(device);
327fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
328fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
329fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiuscoped_refptr<Device> DeviceInfo::GetDevice(const string& device_name) {
330fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  map<string, scoped_refptr<Device>>::iterator iter =
331fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu      devices_.find(device_name);
332fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  if (iter == devices_.end()) {
333fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu    return nullptr;
334fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  }
335fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu  return iter->second;
336fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}
337fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu
338fb39ba4b2ef92f0c9d19f6910a350cd8a14405a0Peter Qiu}  // namespace apmanager
339