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/netlink.h>
20 #include <linux/rtnetlink.h>
21
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
37 #include "apmanager/fake_device_adaptor.h"
38 #include "apmanager/mock_control.h"
39 #include "apmanager/mock_device.h"
40 #include "apmanager/mock_manager.h"
41
42 using shill::ByteString;
43 using shill::Nl80211Message;
44 using shill::RTNLMessage;
45 using std::map;
46 using std::string;
47 using std::vector;
48 using ::testing::_;
49 using ::testing::Mock;
50 using ::testing::ReturnNew;
51
52 namespace apmanager {
53
54 namespace {
55
56 const char kTestDeviceName[] = "test-phy";
57 const char kTestInterface0Name[] = "test-interface0";
58 const char kTestInterface1Name[] = "test-interface1";
59 const uint32_t kTestInterface0Index = 1000;
60 const uint32_t kTestInterface1Index = 1001;
61
62 } // namespace
63
64 class DeviceInfoTest : public testing::Test {
65 public:
DeviceInfoTest()66 DeviceInfoTest()
67 : manager_(&control_interface_),
68 device_info_(&manager_) {}
~DeviceInfoTest()69 virtual ~DeviceInfoTest() {}
70
SetUp()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_;
79
80 ON_CALL(control_interface_, CreateDeviceAdaptorRaw())
81 .WillByDefault(ReturnNew<FakeDeviceAdaptor>());
82 }
83
IsWifiInterface(const string & interface_name)84 bool IsWifiInterface(const string& interface_name) {
85 return device_info_.IsWifiInterface(interface_name);
86 }
87
CreateDeviceInfoFile(const string & interface_name,const string & file_name,const string & contents)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
SendLinkMsg(RTNLMessage::Mode mode,uint32_t interface_index,const string & interface_name)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
VerifyInterfaceList(const vector<Device::WiFiInterface> & interfaces)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
VerifyDeviceList(const vector<scoped_refptr<Device>> & devices)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 }
AddInterface(const Device::WiFiInterface & interface)134 void AddInterface(const Device::WiFiInterface& interface) {
135 device_info_.interface_infos_[interface.iface_index] = interface;
136 }
137
OnWiFiPhyInfoReceived(const Nl80211Message & message)138 void OnWiFiPhyInfoReceived(const Nl80211Message& message) {
139 device_info_.OnWiFiPhyInfoReceived(message);
140 }
141
OnWiFiInterfaceInfoReceived(const Nl80211Message & message)142 void OnWiFiInterfaceInfoReceived(const Nl80211Message& message) {
143 device_info_.OnWiFiInterfaceInfoReceived(message);
144 }
145
OnWiFiInterfacePhyInfoReceived(uint32_t interface_index,const Nl80211Message & message)146 void OnWiFiInterfacePhyInfoReceived(uint32_t interface_index,
147 const Nl80211Message& message) {
148 device_info_.OnWiFiInterfacePhyInfoReceived(interface_index, message);
149 }
150
RegisterDevice(scoped_refptr<Device> device)151 void RegisterDevice(scoped_refptr<Device> device) {
152 device_info_.RegisterDevice(device);
153 }
154
155 protected:
156 MockControl control_interface_;
157 MockManager manager_;
158
159 shill::MockNetlinkManager netlink_manager_;
160 base::ScopedTempDir temp_dir_;
161 base::FilePath device_info_root_;
162 DeviceInfo device_info_;
163 };
164
165 MATCHER_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
184 MATCHER_P(IsInterface, interface, "") {
185 return arg.Equals(interface);
186 }
187
188 MATCHER_P(IsDevice, device_name, "") {
189 return arg->GetDeviceName() == device_name;
190 }
191
TEST_F(DeviceInfoTest,EnumerateDevices)192 TEST_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.
200 message.attributes()->CreateNl80211Attribute(
201 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
202 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
TEST_F(DeviceInfoTest,IsWiFiInterface)214 TEST_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
TEST_F(DeviceInfoTest,InterfaceDetection)227 TEST_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
TEST_F(DeviceInfoTest,ParseWifiInterfaceInfo)293 TEST_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.
307 message.attributes()->CreateNl80211Attribute(
308 NL80211_ATTR_IFINDEX, shill::NetlinkMessage::MessageContext());
309 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);
319 message.attributes()->CreateNl80211Attribute(
320 NL80211_ATTR_IFTYPE, shill::NetlinkMessage::MessageContext());
321 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
TEST_F(DeviceInfoTest,ParsePhyInfoForWifiInterface)328 TEST_F(DeviceInfoTest, ParsePhyInfoForWifiInterface) {
329 // Register a mock device.
330 scoped_refptr<MockDevice> device = new MockDevice(&manager_);
331 device->SetDeviceName(kTestDeviceName);
332 EXPECT_CALL(manager_, RegisterDevice(_)).Times(1);
333 RegisterDevice(device);
334
335 // PHY info message.
336 shill::NewWiphyMessage message;
337 message.attributes()->CreateNl80211Attribute(
338 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
339 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
TEST_F(DeviceInfoTest,ReceivePhyInfoBeforePhyIsEnumerated)360 TEST_F(DeviceInfoTest, ReceivePhyInfoBeforePhyIsEnumerated) {
361 // New interface is detected.
362 Device::WiFiInterface interface(
363 kTestInterface0Name, "", kTestInterface0Index, NL80211_IFTYPE_AP);
364 AddInterface(interface);
365 vector<Device::WiFiInterface> interface_list;
366 interface_list.push_back(interface);
367
368 // Received PHY info for the interface when the corresponding PHY is not
369 // enumerated yet, new device should be created and register to manager.
370 shill::NewWiphyMessage message;
371 message.attributes()->CreateNl80211Attribute(
372 NL80211_ATTR_WIPHY_NAME, shill::NetlinkMessage::MessageContext());
373 message.attributes()->SetStringAttributeValue(NL80211_ATTR_WIPHY_NAME,
374 kTestDeviceName);
375 EXPECT_CALL(manager_, RegisterDevice(IsDevice(kTestDeviceName))).Times(1);
376 OnWiFiInterfacePhyInfoReceived(kTestInterface0Index, message);
377 interface_list[0].device_name = kTestDeviceName;
378 VerifyInterfaceList(interface_list);
379 }
380
TEST_F(DeviceInfoTest,RegisterDevice)381 TEST_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.
389 device_list.push_back(new Device(&manager_, kTestDeviceName, 0));
390 EXPECT_CALL(manager_, RegisterDevice(device_list[0]));
391 RegisterDevice(device_list[0]);
392 VerifyDeviceList(device_list);
393 }
394
395 } // namespace apmanager
396