blob: a31fc927a995999464a44c14cdc6ffd3e288a747 [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/netlink.h>
8
9#include <map>
10#include <string>
11#include <vector>
12
13#include <base/files/file_util.h>
14#include <base/files/scoped_temp_dir.h>
15#include <gmock/gmock.h>
16#include <gtest/gtest.h>
17#include <shill/net/byte_string.h>
18#include <shill/net/mock_netlink_manager.h>
19#include "shill/net/netlink_message_matchers.h"
20#include "shill/net/nl80211_attribute.h"
21#include "shill/net/nl80211_message.h"
22#include <shill/net/rtnl_message.h>
23
24#include "apmanager/mock_device.h"
25#include "apmanager/mock_manager.h"
26
27using shill::ByteString;
28using shill::Nl80211Message;
29using shill::RTNLMessage;
30using std::map;
31using std::string;
32using std::vector;
33using ::testing::_;
34using ::testing::Mock;
35
36namespace apmanager {
37
38namespace {
39
40const char kTestDeviceName[] = "test-phy";
41const char kTestInterface0Name[] = "test-interface0";
42const char kTestInterface1Name[] = "test-interface1";
43const uint32_t kTestInterface0Index = 1000;
44const uint32_t kTestInterface1Index = 1001;
45
46} // namespace
47
48class DeviceInfoTest : public testing::Test {
49 public:
50 DeviceInfoTest() : device_info_(&manager_) {}
51 virtual ~DeviceInfoTest() {}
52
53 virtual void SetUp() {
54 // Setup temporary directory for device info files.
55 CHECK(temp_dir_.CreateUniqueTempDir());
56 device_info_root_ = temp_dir_.path().Append("sys/class/net");
57 device_info_.device_info_root_ = device_info_root_;
58
59 // Setup mock pointers;
60 device_info_.netlink_manager_ = &netlink_manager_;
61 }
62
63 bool IsWifiInterface(const string& interface_name) {
64 return device_info_.IsWifiInterface(interface_name);
65 }
66
67 void CreateDeviceInfoFile(const string& interface_name,
68 const string& file_name,
69 const string& contents) {
70 base::FilePath info_path =
71 device_info_root_.Append(interface_name).Append(file_name);
72 EXPECT_TRUE(base::CreateDirectory(info_path.DirName()));
73 EXPECT_TRUE(base::WriteFile(info_path, contents.c_str(), contents.size()));
74 }
75
76 void SendLinkMsg(RTNLMessage::Mode mode,
77 uint32_t interface_index,
78 const string& interface_name) {
79 RTNLMessage message(RTNLMessage::kTypeLink,
80 mode,
81 0,
82 0,
83 0,
84 interface_index,
85 shill::IPAddress::kFamilyIPv4);
86 message.SetAttribute(static_cast<uint16_t>(IFLA_IFNAME),
87 ByteString(interface_name, true));
88 device_info_.LinkMsgHandler(message);
89 }
90
91 void VerifyInterfaceList(const vector<Device::WiFiInterface>& interfaces) {
92 // Verify number of elements in the interface infos map and interface index
93 // of the elements in the map.
94 EXPECT_EQ(interfaces.size(), device_info_.interface_infos_.size());
95 for (const auto& interface : interfaces) {
96 map<uint32_t, Device::WiFiInterface>::iterator it =
97 device_info_.interface_infos_.find(interface.iface_index);
98 EXPECT_NE(device_info_.interface_infos_.end(), it);
99 EXPECT_TRUE(interface.Equals(it->second));
100 }
101 }
102
103 void VerifyDeviceList(const vector<scoped_refptr<Device>>& devices) {
104 // Verify number of elements in the device map and the elements in the map.
105 EXPECT_EQ(devices.size(), device_info_.devices_.size());
106 for (const auto& device : devices) {
107 map<string, scoped_refptr<Device>>::iterator it =
108 device_info_.devices_.find(device->GetDeviceName());
109 EXPECT_NE(device_info_.devices_.end(), it);
110 EXPECT_EQ(device, it->second);
111 }
112 }
113 void AddInterface(const Device::WiFiInterface& interface) {
114 device_info_.interface_infos_[interface.iface_index] = interface;
115 }
116
Peter Qiu1ff67a72014-11-22 07:06:10 -0800117 void OnWiFiPhyInfoReceived(const Nl80211Message& message) {
118 device_info_.OnWiFiPhyInfoReceived(message);
119 }
120
Peter Qiufb39ba42014-11-21 09:09:59 -0800121 void OnWiFiInterfaceInfoReceived(const Nl80211Message& message) {
122 device_info_.OnWiFiInterfaceInfoReceived(message);
123 }
124
125 void OnWiFiInterfacePhyInfoReceived(uint32_t interface_index,
126 const Nl80211Message& message) {
127 device_info_.OnWiFiInterfacePhyInfoReceived(interface_index, message);
128 }
129
130 void RegisterDevice(scoped_refptr<Device> device) {
131 device_info_.RegisterDevice(device);
132 }
133
134 protected:
135 DeviceInfo device_info_;
136 MockManager manager_;
137 shill::MockNetlinkManager netlink_manager_;
138 base::ScopedTempDir temp_dir_;
139 base::FilePath device_info_root_;
140};
141
142MATCHER_P2(IsGetInfoMessage, command, index, "") {
143 if (arg->message_type() != Nl80211Message::GetMessageType()) {
144 return false;
145 }
146 const Nl80211Message *msg = reinterpret_cast<const Nl80211Message *>(arg);
147 if (msg->command() != command) {
148 return false;
149 }
150 uint32_t interface_index;
151 if (!msg->const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFINDEX,
152 &interface_index)) {
153 return false;
154 }
155 // kInterfaceIndex is signed, but the attribute as handed from the kernel
156 // is unsigned. We're silently casting it away with this assignment.
157 uint32_t test_interface_index = index;
158 return interface_index == test_interface_index;
159}
160
161MATCHER_P(IsInterface, interface, "") {
162 return arg.Equals(interface);
163}
164
Peter Qiu1ff67a72014-11-22 07:06:10 -0800165MATCHER_P(IsDevice, device_name, "") {
166 return arg->GetDeviceName() == device_name;
167}
168
169TEST_F(DeviceInfoTest, EnumerateDevices) {
170 shill::NewWiphyMessage message;
171
172 // No device name in the message, failed to create device.
173 EXPECT_CALL(manager_, RegisterDevice(_)).Times(0);
174 OnWiFiPhyInfoReceived(message);
175
176 // Device name in the message, device should be created/register to manager.
Samuel Tan31096662015-02-04 14:44:10 -0800177 message.attributes()->CreateNl80211Attribute(
178 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
Peter Qiu1ff67a72014-11-22 07:06:10 -0800179 message.attributes()->SetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
180 kTestDeviceName);
181 EXPECT_CALL(manager_, RegisterDevice(IsDevice(kTestDeviceName))).Times(1);
182 OnWiFiPhyInfoReceived(message);
183 Mock::VerifyAndClearExpectations(&manager_);
184
185 // Receive a message for a device already created, should not create/register
186 // device again.
187 EXPECT_CALL(manager_, RegisterDevice(_)).Times(0);
188 OnWiFiPhyInfoReceived(message);
189}
190
Peter Qiufb39ba42014-11-21 09:09:59 -0800191TEST_F(DeviceInfoTest, IsWiFiInterface) {
192 // No device info file exist, not a wifi interface.
193 EXPECT_FALSE(IsWifiInterface(kTestInterface0Name));
194
195 // Device info for an ethernet device, not a wifi interface
196 CreateDeviceInfoFile(kTestInterface0Name, "uevent", "INTERFACE=eth0\n");
197 EXPECT_FALSE(IsWifiInterface(kTestInterface0Name));
198
199 // Device info for a wifi interface.
200 CreateDeviceInfoFile(kTestInterface1Name, "uevent", "DEVTYPE=wlan\n");
201 EXPECT_TRUE(IsWifiInterface(kTestInterface1Name));
202}
203
204TEST_F(DeviceInfoTest, InterfaceDetection) {
205 vector<Device::WiFiInterface> interface_list;
206 // Ignore non-wifi interface.
207 SendLinkMsg(RTNLMessage::kModeAdd,
208 kTestInterface0Index,
209 kTestInterface0Name);
210 VerifyInterfaceList(interface_list);
211
212 // AddLink event for wifi interface.
213 CreateDeviceInfoFile(kTestInterface0Name, "uevent", "DEVTYPE=wlan\n");
214 EXPECT_CALL(netlink_manager_, SendNl80211Message(
215 IsGetInfoMessage(NL80211_CMD_GET_INTERFACE, kTestInterface0Index),
216 _, _, _)).Times(1);
217 SendLinkMsg(RTNLMessage::kModeAdd,
218 kTestInterface0Index,
219 kTestInterface0Name);
220 interface_list.push_back(Device::WiFiInterface(
221 kTestInterface0Name, "", kTestInterface0Index, 0));
222 VerifyInterfaceList(interface_list);
223 Mock::VerifyAndClearExpectations(&netlink_manager_);
224
225 // AddLink event for another wifi interface.
226 CreateDeviceInfoFile(kTestInterface1Name, "uevent", "DEVTYPE=wlan\n");
227 EXPECT_CALL(netlink_manager_, SendNl80211Message(
228 IsGetInfoMessage(NL80211_CMD_GET_INTERFACE, kTestInterface1Index),
229 _, _, _)).Times(1);
230 SendLinkMsg(RTNLMessage::kModeAdd,
231 kTestInterface1Index,
232 kTestInterface1Name);
233 interface_list.push_back(Device::WiFiInterface(
234 kTestInterface1Name, "", kTestInterface1Index, 0));
235 VerifyInterfaceList(interface_list);
236 Mock::VerifyAndClearExpectations(&netlink_manager_);
237
238 // AddLink event for an interface that's already added, no change to interface
239 // list.
240 EXPECT_CALL(netlink_manager_, SendNl80211Message(_, _, _, _)).Times(0);
241 SendLinkMsg(RTNLMessage::kModeAdd,
242 kTestInterface0Index,
243 kTestInterface0Name);
244 VerifyInterfaceList(interface_list);
245 Mock::VerifyAndClearExpectations(&netlink_manager_);
246
247 // Remove the first wifi interface.
248 SendLinkMsg(RTNLMessage::kModeDelete,
249 kTestInterface0Index,
250 kTestInterface0Name);
251 interface_list.clear();
252 interface_list.push_back(Device::WiFiInterface(
253 kTestInterface1Name, "", kTestInterface1Index, 0));
254 VerifyInterfaceList(interface_list);
255
256 // Remove the non-exist interface, no change to the list.
257 SendLinkMsg(RTNLMessage::kModeDelete,
258 kTestInterface0Index,
259 kTestInterface0Name);
260 VerifyInterfaceList(interface_list);
261
262 // Remove the last interface, list should be empty now.
263 SendLinkMsg(RTNLMessage::kModeDelete,
264 kTestInterface1Index,
265 kTestInterface1Name);
266 interface_list.clear();
267 VerifyInterfaceList(interface_list);
268}
269
270TEST_F(DeviceInfoTest, ParseWifiInterfaceInfo) {
271 // Add an interface without interface type info.
272 Device::WiFiInterface interface(
273 kTestInterface0Name, "", kTestInterface0Index, 0);
274 AddInterface(interface);
275 vector<Device::WiFiInterface> interface_list;
276 interface_list.push_back(interface);
277
278 // Message contain no interface index, no change to the interface info.
279 shill::NewInterfaceMessage message;
280 OnWiFiInterfaceInfoReceived(message);
281 VerifyInterfaceList(interface_list);
282
283 // Message contain no interface type, no change to the interface info.
Samuel Tan31096662015-02-04 14:44:10 -0800284 message.attributes()->CreateNl80211Attribute(
285 NL80211_ATTR_IFINDEX, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800286 message.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
287 kTestInterface0Index);
288 OnWiFiInterfaceInfoReceived(message);
289
290 // Message contain interface type, interface info should be updated with
291 // the interface type, and a new Nl80211 message should be send to query for
292 // the PHY info.
293 EXPECT_CALL(netlink_manager_, SendNl80211Message(
294 IsGetInfoMessage(NL80211_CMD_GET_WIPHY, kTestInterface0Index),
295 _, _, _)).Times(1);
Samuel Tan31096662015-02-04 14:44:10 -0800296 message.attributes()->CreateNl80211Attribute(
297 NL80211_ATTR_IFTYPE, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800298 message.attributes()->SetU32AttributeValue(NL80211_ATTR_IFTYPE,
299 NL80211_IFTYPE_AP);
300 OnWiFiInterfaceInfoReceived(message);
301 interface_list[0].iface_type = NL80211_IFTYPE_AP;
302 VerifyInterfaceList(interface_list);
303}
304
305TEST_F(DeviceInfoTest, ParsePhyInfoForWifiInterface) {
306 // Register a mock device.
307 scoped_refptr<MockDevice> device = new MockDevice();
308 device->SetDeviceName(kTestDeviceName);
309 EXPECT_CALL(manager_, RegisterDevice(_)).Times(1);
310 RegisterDevice(device);
311
312 // PHY info message.
313 shill::NewWiphyMessage message;
Samuel Tan31096662015-02-04 14:44:10 -0800314 message.attributes()->CreateNl80211Attribute(
315 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800316 message.attributes()->SetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
317 kTestDeviceName);
318
319 // Receive PHY info message for an interface that have not been detected yet.
320 EXPECT_CALL(*device.get(), RegisterInterface(_)).Times(0);
321 OnWiFiInterfacePhyInfoReceived(kTestInterface0Index, message);
322
323 // Pretend interface is detected through AddLink with interface info already
324 // received (interface type), and still missing PHY info for that interface.
325 Device::WiFiInterface interface(
326 kTestInterface0Name, "", kTestInterface0Index, NL80211_IFTYPE_AP);
327 AddInterface(interface);
328
329 // PHY info is received for a detected interface, should register that
330 // interface to the corresponding Device.
331 interface.device_name = kTestDeviceName;
332 EXPECT_CALL(*device.get(),
333 RegisterInterface(IsInterface(interface))).Times(1);
334 OnWiFiInterfacePhyInfoReceived(kTestInterface0Index, message);
335}
336
337TEST_F(DeviceInfoTest, ReceivePhyInfoBeforePhyIsEnumerated) {
338 // New interface is detected.
339 Device::WiFiInterface interface(
340 kTestInterface0Name, "", kTestInterface0Index, NL80211_IFTYPE_AP);
341 AddInterface(interface);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800342 vector<Device::WiFiInterface> interface_list;
343 interface_list.push_back(interface);
Peter Qiufb39ba42014-11-21 09:09:59 -0800344
345 // Received PHY info for the interface when the corresponding PHY is not
Peter Qiu1ff67a72014-11-22 07:06:10 -0800346 // enumerated yet, new device should be created and register to manager.
Peter Qiufb39ba42014-11-21 09:09:59 -0800347 shill::NewWiphyMessage message;
Samuel Tan31096662015-02-04 14:44:10 -0800348 message.attributes()->CreateNl80211Attribute(
349 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800350 message.attributes()->SetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
351 kTestDeviceName);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800352 EXPECT_CALL(manager_, RegisterDevice(IsDevice(kTestDeviceName))).Times(1);
Peter Qiufb39ba42014-11-21 09:09:59 -0800353 OnWiFiInterfacePhyInfoReceived(kTestInterface0Index, message);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800354 interface_list[0].device_name = kTestDeviceName;
355 VerifyInterfaceList(interface_list);
Peter Qiufb39ba42014-11-21 09:09:59 -0800356}
357
358TEST_F(DeviceInfoTest, RegisterDevice) {
359 vector<scoped_refptr<Device>> device_list;
360
361 // Register a nullptr.
362 RegisterDevice(nullptr);
363 VerifyDeviceList(device_list);
364
365 // Register a device.
Peter Qiu7e0ffcf2014-12-02 12:53:27 -0800366 device_list.push_back(new Device(&manager_, kTestDeviceName));
Peter Qiufb39ba42014-11-21 09:09:59 -0800367 EXPECT_CALL(manager_, RegisterDevice(device_list[0]));
368 RegisterDevice(device_list[0]);
369 VerifyDeviceList(device_list);
370}
371
372} // namespace apmanager