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