blob: 157d1bebf7c687bff2c65883e09d9f023efeb58f [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/netlink.h>
Paul Stewart23939562015-07-28 15:12:40 -070020#include <linux/rtnetlink.h>
Peter Qiufb39ba42014-11-21 09:09:59 -080021
22#include <map>
23#include <string>
24#include <vector>
25
26#include <base/files/file_util.h>
27#include <base/files/scoped_temp_dir.h>
28#include <gmock/gmock.h>
29#include <gtest/gtest.h>
30#include <shill/net/byte_string.h>
31#include <shill/net/mock_netlink_manager.h>
32#include "shill/net/netlink_message_matchers.h"
33#include "shill/net/nl80211_attribute.h"
34#include "shill/net/nl80211_message.h"
35#include <shill/net/rtnl_message.h>
36
Peter Qiuf9335402015-11-16 12:09:16 -080037#include "apmanager/fake_device_adaptor.h"
38#include "apmanager/mock_control.h"
Peter Qiufb39ba42014-11-21 09:09:59 -080039#include "apmanager/mock_device.h"
40#include "apmanager/mock_manager.h"
41
42using shill::ByteString;
43using shill::Nl80211Message;
44using shill::RTNLMessage;
45using std::map;
46using std::string;
47using std::vector;
48using ::testing::_;
49using ::testing::Mock;
Peter Qiuf9335402015-11-16 12:09:16 -080050using ::testing::ReturnNew;
Peter Qiufb39ba42014-11-21 09:09:59 -080051
52namespace apmanager {
53
54namespace {
55
56const char kTestDeviceName[] = "test-phy";
57const char kTestInterface0Name[] = "test-interface0";
58const char kTestInterface1Name[] = "test-interface1";
59const uint32_t kTestInterface0Index = 1000;
60const uint32_t kTestInterface1Index = 1001;
61
62} // namespace
63
64class DeviceInfoTest : public testing::Test {
65 public:
Peter Qiuf9335402015-11-16 12:09:16 -080066 DeviceInfoTest()
67 : manager_(&control_interface_),
68 device_info_(&manager_) {}
Peter Qiufb39ba42014-11-21 09:09:59 -080069 virtual ~DeviceInfoTest() {}
70
71 virtual void SetUp() {
72 // Setup temporary directory for device info files.
73 CHECK(temp_dir_.CreateUniqueTempDir());
74 device_info_root_ = temp_dir_.path().Append("sys/class/net");
75 device_info_.device_info_root_ = device_info_root_;
76
77 // Setup mock pointers;
78 device_info_.netlink_manager_ = &netlink_manager_;
Peter Qiuf9335402015-11-16 12:09:16 -080079
80 ON_CALL(control_interface_, CreateDeviceAdaptorRaw())
81 .WillByDefault(ReturnNew<FakeDeviceAdaptor>());
Peter Qiufb39ba42014-11-21 09:09:59 -080082 }
83
84 bool IsWifiInterface(const string& interface_name) {
85 return device_info_.IsWifiInterface(interface_name);
86 }
87
88 void CreateDeviceInfoFile(const string& interface_name,
89 const string& file_name,
90 const string& contents) {
91 base::FilePath info_path =
92 device_info_root_.Append(interface_name).Append(file_name);
93 EXPECT_TRUE(base::CreateDirectory(info_path.DirName()));
94 EXPECT_TRUE(base::WriteFile(info_path, contents.c_str(), contents.size()));
95 }
96
97 void SendLinkMsg(RTNLMessage::Mode mode,
98 uint32_t interface_index,
99 const string& interface_name) {
100 RTNLMessage message(RTNLMessage::kTypeLink,
101 mode,
102 0,
103 0,
104 0,
105 interface_index,
106 shill::IPAddress::kFamilyIPv4);
107 message.SetAttribute(static_cast<uint16_t>(IFLA_IFNAME),
108 ByteString(interface_name, true));
109 device_info_.LinkMsgHandler(message);
110 }
111
112 void VerifyInterfaceList(const vector<Device::WiFiInterface>& interfaces) {
113 // Verify number of elements in the interface infos map and interface index
114 // of the elements in the map.
115 EXPECT_EQ(interfaces.size(), device_info_.interface_infos_.size());
116 for (const auto& interface : interfaces) {
117 map<uint32_t, Device::WiFiInterface>::iterator it =
118 device_info_.interface_infos_.find(interface.iface_index);
119 EXPECT_NE(device_info_.interface_infos_.end(), it);
120 EXPECT_TRUE(interface.Equals(it->second));
121 }
122 }
123
124 void VerifyDeviceList(const vector<scoped_refptr<Device>>& devices) {
125 // Verify number of elements in the device map and the elements in the map.
126 EXPECT_EQ(devices.size(), device_info_.devices_.size());
127 for (const auto& device : devices) {
128 map<string, scoped_refptr<Device>>::iterator it =
129 device_info_.devices_.find(device->GetDeviceName());
130 EXPECT_NE(device_info_.devices_.end(), it);
131 EXPECT_EQ(device, it->second);
132 }
133 }
134 void AddInterface(const Device::WiFiInterface& interface) {
135 device_info_.interface_infos_[interface.iface_index] = interface;
136 }
137
Peter Qiu1ff67a72014-11-22 07:06:10 -0800138 void OnWiFiPhyInfoReceived(const Nl80211Message& message) {
139 device_info_.OnWiFiPhyInfoReceived(message);
140 }
141
Peter Qiufb39ba42014-11-21 09:09:59 -0800142 void OnWiFiInterfaceInfoReceived(const Nl80211Message& message) {
143 device_info_.OnWiFiInterfaceInfoReceived(message);
144 }
145
146 void OnWiFiInterfacePhyInfoReceived(uint32_t interface_index,
147 const Nl80211Message& message) {
148 device_info_.OnWiFiInterfacePhyInfoReceived(interface_index, message);
149 }
150
151 void RegisterDevice(scoped_refptr<Device> device) {
152 device_info_.RegisterDevice(device);
153 }
154
155 protected:
Peter Qiuf9335402015-11-16 12:09:16 -0800156 MockControl control_interface_;
Peter Qiufb39ba42014-11-21 09:09:59 -0800157 MockManager manager_;
Peter Qiuf9335402015-11-16 12:09:16 -0800158
Peter Qiufb39ba42014-11-21 09:09:59 -0800159 shill::MockNetlinkManager netlink_manager_;
160 base::ScopedTempDir temp_dir_;
161 base::FilePath device_info_root_;
Peter Qiuf9335402015-11-16 12:09:16 -0800162 DeviceInfo device_info_;
Peter Qiufb39ba42014-11-21 09:09:59 -0800163};
164
165MATCHER_P2(IsGetInfoMessage, command, index, "") {
166 if (arg->message_type() != Nl80211Message::GetMessageType()) {
167 return false;
168 }
169 const Nl80211Message *msg = reinterpret_cast<const Nl80211Message *>(arg);
170 if (msg->command() != command) {
171 return false;
172 }
173 uint32_t interface_index;
174 if (!msg->const_attributes()->GetU32AttributeValue(NL80211_ATTR_IFINDEX,
175 &interface_index)) {
176 return false;
177 }
178 // kInterfaceIndex is signed, but the attribute as handed from the kernel
179 // is unsigned. We're silently casting it away with this assignment.
180 uint32_t test_interface_index = index;
181 return interface_index == test_interface_index;
182}
183
184MATCHER_P(IsInterface, interface, "") {
185 return arg.Equals(interface);
186}
187
Peter Qiu1ff67a72014-11-22 07:06:10 -0800188MATCHER_P(IsDevice, device_name, "") {
189 return arg->GetDeviceName() == device_name;
190}
191
192TEST_F(DeviceInfoTest, EnumerateDevices) {
193 shill::NewWiphyMessage message;
194
195 // No device name in the message, failed to create device.
196 EXPECT_CALL(manager_, RegisterDevice(_)).Times(0);
197 OnWiFiPhyInfoReceived(message);
198
199 // Device name in the message, device should be created/register to manager.
Samuel Tan31096662015-02-04 14:44:10 -0800200 message.attributes()->CreateNl80211Attribute(
201 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
Peter Qiu1ff67a72014-11-22 07:06:10 -0800202 message.attributes()->SetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
203 kTestDeviceName);
204 EXPECT_CALL(manager_, RegisterDevice(IsDevice(kTestDeviceName))).Times(1);
205 OnWiFiPhyInfoReceived(message);
206 Mock::VerifyAndClearExpectations(&manager_);
207
208 // Receive a message for a device already created, should not create/register
209 // device again.
210 EXPECT_CALL(manager_, RegisterDevice(_)).Times(0);
211 OnWiFiPhyInfoReceived(message);
212}
213
Peter Qiufb39ba42014-11-21 09:09:59 -0800214TEST_F(DeviceInfoTest, IsWiFiInterface) {
215 // No device info file exist, not a wifi interface.
216 EXPECT_FALSE(IsWifiInterface(kTestInterface0Name));
217
218 // Device info for an ethernet device, not a wifi interface
219 CreateDeviceInfoFile(kTestInterface0Name, "uevent", "INTERFACE=eth0\n");
220 EXPECT_FALSE(IsWifiInterface(kTestInterface0Name));
221
222 // Device info for a wifi interface.
223 CreateDeviceInfoFile(kTestInterface1Name, "uevent", "DEVTYPE=wlan\n");
224 EXPECT_TRUE(IsWifiInterface(kTestInterface1Name));
225}
226
227TEST_F(DeviceInfoTest, InterfaceDetection) {
228 vector<Device::WiFiInterface> interface_list;
229 // Ignore non-wifi interface.
230 SendLinkMsg(RTNLMessage::kModeAdd,
231 kTestInterface0Index,
232 kTestInterface0Name);
233 VerifyInterfaceList(interface_list);
234
235 // AddLink event for wifi interface.
236 CreateDeviceInfoFile(kTestInterface0Name, "uevent", "DEVTYPE=wlan\n");
237 EXPECT_CALL(netlink_manager_, SendNl80211Message(
238 IsGetInfoMessage(NL80211_CMD_GET_INTERFACE, kTestInterface0Index),
239 _, _, _)).Times(1);
240 SendLinkMsg(RTNLMessage::kModeAdd,
241 kTestInterface0Index,
242 kTestInterface0Name);
243 interface_list.push_back(Device::WiFiInterface(
244 kTestInterface0Name, "", kTestInterface0Index, 0));
245 VerifyInterfaceList(interface_list);
246 Mock::VerifyAndClearExpectations(&netlink_manager_);
247
248 // AddLink event for another wifi interface.
249 CreateDeviceInfoFile(kTestInterface1Name, "uevent", "DEVTYPE=wlan\n");
250 EXPECT_CALL(netlink_manager_, SendNl80211Message(
251 IsGetInfoMessage(NL80211_CMD_GET_INTERFACE, kTestInterface1Index),
252 _, _, _)).Times(1);
253 SendLinkMsg(RTNLMessage::kModeAdd,
254 kTestInterface1Index,
255 kTestInterface1Name);
256 interface_list.push_back(Device::WiFiInterface(
257 kTestInterface1Name, "", kTestInterface1Index, 0));
258 VerifyInterfaceList(interface_list);
259 Mock::VerifyAndClearExpectations(&netlink_manager_);
260
261 // AddLink event for an interface that's already added, no change to interface
262 // list.
263 EXPECT_CALL(netlink_manager_, SendNl80211Message(_, _, _, _)).Times(0);
264 SendLinkMsg(RTNLMessage::kModeAdd,
265 kTestInterface0Index,
266 kTestInterface0Name);
267 VerifyInterfaceList(interface_list);
268 Mock::VerifyAndClearExpectations(&netlink_manager_);
269
270 // Remove the first wifi interface.
271 SendLinkMsg(RTNLMessage::kModeDelete,
272 kTestInterface0Index,
273 kTestInterface0Name);
274 interface_list.clear();
275 interface_list.push_back(Device::WiFiInterface(
276 kTestInterface1Name, "", kTestInterface1Index, 0));
277 VerifyInterfaceList(interface_list);
278
279 // Remove the non-exist interface, no change to the list.
280 SendLinkMsg(RTNLMessage::kModeDelete,
281 kTestInterface0Index,
282 kTestInterface0Name);
283 VerifyInterfaceList(interface_list);
284
285 // Remove the last interface, list should be empty now.
286 SendLinkMsg(RTNLMessage::kModeDelete,
287 kTestInterface1Index,
288 kTestInterface1Name);
289 interface_list.clear();
290 VerifyInterfaceList(interface_list);
291}
292
293TEST_F(DeviceInfoTest, ParseWifiInterfaceInfo) {
294 // Add an interface without interface type info.
295 Device::WiFiInterface interface(
296 kTestInterface0Name, "", kTestInterface0Index, 0);
297 AddInterface(interface);
298 vector<Device::WiFiInterface> interface_list;
299 interface_list.push_back(interface);
300
301 // Message contain no interface index, no change to the interface info.
302 shill::NewInterfaceMessage message;
303 OnWiFiInterfaceInfoReceived(message);
304 VerifyInterfaceList(interface_list);
305
306 // Message contain no interface type, no change to the interface info.
Samuel Tan31096662015-02-04 14:44:10 -0800307 message.attributes()->CreateNl80211Attribute(
308 NL80211_ATTR_IFINDEX, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800309 message.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
310 kTestInterface0Index);
311 OnWiFiInterfaceInfoReceived(message);
312
313 // Message contain interface type, interface info should be updated with
314 // the interface type, and a new Nl80211 message should be send to query for
315 // the PHY info.
316 EXPECT_CALL(netlink_manager_, SendNl80211Message(
317 IsGetInfoMessage(NL80211_CMD_GET_WIPHY, kTestInterface0Index),
318 _, _, _)).Times(1);
Samuel Tan31096662015-02-04 14:44:10 -0800319 message.attributes()->CreateNl80211Attribute(
320 NL80211_ATTR_IFTYPE, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800321 message.attributes()->SetU32AttributeValue(NL80211_ATTR_IFTYPE,
322 NL80211_IFTYPE_AP);
323 OnWiFiInterfaceInfoReceived(message);
324 interface_list[0].iface_type = NL80211_IFTYPE_AP;
325 VerifyInterfaceList(interface_list);
326}
327
328TEST_F(DeviceInfoTest, ParsePhyInfoForWifiInterface) {
329 // Register a mock device.
Peter Qiuf9335402015-11-16 12:09:16 -0800330 scoped_refptr<MockDevice> device = new MockDevice(&manager_);
Peter Qiufb39ba42014-11-21 09:09:59 -0800331 device->SetDeviceName(kTestDeviceName);
332 EXPECT_CALL(manager_, RegisterDevice(_)).Times(1);
333 RegisterDevice(device);
334
335 // PHY info message.
336 shill::NewWiphyMessage message;
Samuel Tan31096662015-02-04 14:44:10 -0800337 message.attributes()->CreateNl80211Attribute(
338 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800339 message.attributes()->SetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
340 kTestDeviceName);
341
342 // Receive PHY info message for an interface that have not been detected yet.
343 EXPECT_CALL(*device.get(), RegisterInterface(_)).Times(0);
344 OnWiFiInterfacePhyInfoReceived(kTestInterface0Index, message);
345
346 // Pretend interface is detected through AddLink with interface info already
347 // received (interface type), and still missing PHY info for that interface.
348 Device::WiFiInterface interface(
349 kTestInterface0Name, "", kTestInterface0Index, NL80211_IFTYPE_AP);
350 AddInterface(interface);
351
352 // PHY info is received for a detected interface, should register that
353 // interface to the corresponding Device.
354 interface.device_name = kTestDeviceName;
355 EXPECT_CALL(*device.get(),
356 RegisterInterface(IsInterface(interface))).Times(1);
357 OnWiFiInterfacePhyInfoReceived(kTestInterface0Index, message);
358}
359
360TEST_F(DeviceInfoTest, ReceivePhyInfoBeforePhyIsEnumerated) {
361 // New interface is detected.
362 Device::WiFiInterface interface(
363 kTestInterface0Name, "", kTestInterface0Index, NL80211_IFTYPE_AP);
364 AddInterface(interface);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800365 vector<Device::WiFiInterface> interface_list;
366 interface_list.push_back(interface);
Peter Qiufb39ba42014-11-21 09:09:59 -0800367
368 // Received PHY info for the interface when the corresponding PHY is not
Peter Qiu1ff67a72014-11-22 07:06:10 -0800369 // enumerated yet, new device should be created and register to manager.
Peter Qiufb39ba42014-11-21 09:09:59 -0800370 shill::NewWiphyMessage message;
Samuel Tan31096662015-02-04 14:44:10 -0800371 message.attributes()->CreateNl80211Attribute(
372 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
Peter Qiufb39ba42014-11-21 09:09:59 -0800373 message.attributes()->SetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
374 kTestDeviceName);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800375 EXPECT_CALL(manager_, RegisterDevice(IsDevice(kTestDeviceName))).Times(1);
Peter Qiufb39ba42014-11-21 09:09:59 -0800376 OnWiFiInterfacePhyInfoReceived(kTestInterface0Index, message);
Peter Qiu1ff67a72014-11-22 07:06:10 -0800377 interface_list[0].device_name = kTestDeviceName;
378 VerifyInterfaceList(interface_list);
Peter Qiufb39ba42014-11-21 09:09:59 -0800379}
380
381TEST_F(DeviceInfoTest, RegisterDevice) {
382 vector<scoped_refptr<Device>> device_list;
383
384 // Register a nullptr.
385 RegisterDevice(nullptr);
386 VerifyDeviceList(device_list);
387
388 // Register a device.
Peter Qiuf9335402015-11-16 12:09:16 -0800389 device_list.push_back(new Device(&manager_, kTestDeviceName, 0));
Peter Qiufb39ba42014-11-21 09:09:59 -0800390 EXPECT_CALL(manager_, RegisterDevice(device_list[0]));
391 RegisterDevice(device_list[0]);
392 VerifyDeviceList(device_list);
393}
394
395} // namespace apmanager