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