blob: 706a16188d39b87b494a9aa3a809142039431d4b [file] [log] [blame]
Peter Qiu326b6cf2015-09-02 11:11:42 -07001//
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//
Peter Qiufb39ba42014-11-21 09:09:59 -080016
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>
Nathan Bullock74cfdc92015-04-13 10:39:50 -040026#include <shill/net/ndisc.h>
Peter Qiufb39ba42014-11-21 09:09:59 -080027#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>
Peter Qiufb39ba42014-11-21 09:09:59 -080033
Peter Qiuf9335402015-11-16 12:09:16 -080034#include "apmanager/control_interface.h"
Peter Qiufb39ba42014-11-21 09:09:59 -080035#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()),
Peter Qiuf9335402015-11-16 12:09:16 -080059 rtnl_handler_(RTNLHandler::GetInstance()),
60 device_identifier_(0) {
Peter Qiufb39ba42014-11-21 09:09:59 -080061}
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.
Nathan Bullock74cfdc92015-04-13 10:39:50 -040081 rtnl_handler_->Start(RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
82 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
83 RTMGRP_ND_USEROPT);
Peter Qiufb39ba42014-11-21 09:09:59 -080084 link_listener_.reset(
85 new RTNLListener(RTNLHandler::kRequestLink, link_callback_));
Peter Qiu1ff67a72014-11-22 07:06:10 -080086 // Request link infos.
87 rtnl_handler_->RequestDump(RTNLHandler::kRequestLink);
Peter Qiufb39ba42014-11-21 09:09:59 -080088}
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
Peter Qiu1ff67a72014-11-22 07:06:10 -0800114 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
Peter Qiuf9335402015-11-16 12:09:16 -0800126 scoped_refptr<Device> device =
127 new Device(manager_, device_name, device_identifier_++);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800128 device->ParseWiphyCapability(msg);
Peter Qiufb39ba42014-11-21 09:09:59 -0800129
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);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800306 // Create device if it is not enumerated yet.
Peter Qiufb39ba42014-11-21 09:09:59 -0800307 if (!device) {
Peter Qiuf9335402015-11-16 12:09:16 -0800308 device =
309 new Device(manager_, device_name, device_identifier_++);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800310 device->ParseWiphyCapability(msg);
311
312 // Register device
313 RegisterDevice(device);
Peter Qiufb39ba42014-11-21 09:09:59 -0800314 }
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