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