blob: 25803a03ad1871a8b9afd9d37fa56a61938219ed [file] [log] [blame]
Chris Masone34af2182011-08-22 11:59:36 -07001// Copyright (c) 2011 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 "shill/wifi_service.h"
6
mukesh agrawald835b202011-10-07 15:26:47 -07007#include <map>
Chris Masone34af2182011-08-22 11:59:36 -07008#include <string>
9#include <vector>
10
11#include <base/string_util.h>
12#include <chromeos/dbus/service_constants.h>
13#include <gmock/gmock.h>
14#include <gtest/gtest.h>
15
Paul Stewart26b327e2011-10-19 11:38:09 -070016#include "shill/event_dispatcher.h"
Chris Masone34af2182011-08-22 11:59:36 -070017#include "shill/manager.h"
18#include "shill/mock_adaptors.h"
19#include "shill/mock_control.h"
20#include "shill/mock_service.h"
21#include "shill/mock_store.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070022#include "shill/mock_wifi.h"
Chris Masone34af2182011-08-22 11:59:36 -070023#include "shill/property_store_unittest.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070024#include "shill/wpa_supplicant.h"
Chris Masone34af2182011-08-22 11:59:36 -070025
mukesh agrawald835b202011-10-07 15:26:47 -070026using std::map;
Chris Masone34af2182011-08-22 11:59:36 -070027using std::string;
28using std::vector;
29
30namespace shill {
Paul Stewartd08f4432011-11-04 07:48:20 -070031using ::testing::_;
32using ::testing::DoAll;
mukesh agrawal6e277772011-09-29 15:04:23 -070033using ::testing::NiceMock;
Paul Stewartd08f4432011-11-04 07:48:20 -070034using ::testing::Return;
35using ::testing::SetArgumentPointee;
36using ::testing::StrEq;
Chris Masone34af2182011-08-22 11:59:36 -070037
38class WiFiServiceTest : public PropertyStoreTest {
39 public:
mukesh agrawal6e277772011-09-29 15:04:23 -070040 WiFiServiceTest() : wifi_(
41 new NiceMock<MockWiFi>(
42 control_interface(),
43 dispatcher(),
44 manager(),
45 "wifi",
46 fake_mac,
47 0)) {}
Chris Masone34af2182011-08-22 11:59:36 -070048 virtual ~WiFiServiceTest() {}
mukesh agrawal6e277772011-09-29 15:04:23 -070049
50 protected:
51 static const char fake_mac[];
52 scoped_refptr<MockWiFi> wifi() { return wifi_; }
53
54 private:
55 scoped_refptr<MockWiFi> wifi_;
Chris Masone34af2182011-08-22 11:59:36 -070056};
57
mukesh agrawal6e277772011-09-29 15:04:23 -070058// static
59const char WiFiServiceTest::fake_mac[] = "AaBBcCDDeeFF";
60
Paul Stewartd08f4432011-11-04 07:48:20 -070061class WiFiServiceSecurityTest : public WiFiServiceTest {
62 public:
63 WiFiServiceRefPtr CreateServiceWithSecurity(const string &security) {
Gaurav Shahda6218a2011-11-11 12:09:33 -080064 vector<uint8_t> ssid(5);
Paul Stewartd08f4432011-11-04 07:48:20 -070065 ssid.push_back(0xff);
66
67 return new WiFiService(control_interface(),
68 dispatcher(),
69 manager(),
70 wifi(),
71 ssid,
72 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -080073 security,
74 false);
Paul Stewartd08f4432011-11-04 07:48:20 -070075 }
76
77 bool TestStorageSecurityIs(WiFiServiceRefPtr wifi_service,
78 const string &security) {
79 string id = wifi_service->GetStorageIdentifier();
80 size_t mac_pos = id.find(StringToLowerASCII(string(fake_mac)));
81 EXPECT_NE(mac_pos, string::npos);
82 size_t mode_pos = id.find(string(flimflam::kModeManaged), mac_pos);
83 EXPECT_NE(mode_pos, string::npos);
84 return id.find(string(security), mode_pos) != string::npos;
85 }
86
87 // Test that a service that is created with security |from_security|
88 // gets by default a storage identifier with |to_security| as its
89 // security component.
90 bool TestStorageMapping(const string &from_security,
91 const string &to_security) {
92 WiFiServiceRefPtr wifi_service = CreateServiceWithSecurity(from_security);
93 return TestStorageSecurityIs(wifi_service, to_security);
94 }
95
96 // Test whether a service of type |service_security| can load from a
97 // storage interface containing an entry for |storage_security|.
98 // Make sure the result meets |expectation|. If |expectation| is
99 // true, also make sure the service storage identifier changes to
100 // match |storage_security|.
101 bool TestLoadMapping(const string &service_security,
102 const string &storage_security,
103 bool expectation) {
104 WiFiServiceRefPtr wifi_service =
105 CreateServiceWithSecurity(service_security);
106 NiceMock<MockStore> mock_store;
107 const string storage_id =
108 wifi_service->GetStorageIdentifierForSecurity(storage_security);
109 EXPECT_CALL(mock_store, ContainsGroup(_))
110 .WillRepeatedly(Return(false));
111 EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
112 .WillRepeatedly(Return(true));
113 bool is_loadable = wifi_service->IsLoadableFrom(&mock_store);
114 EXPECT_EQ(expectation, is_loadable);
115 bool is_loaded = wifi_service->Load(&mock_store);
116 EXPECT_EQ(expectation, is_loaded);
117
118 if (expectation != is_loadable || expectation != is_loaded) {
119 return false;
120 } else if (!expectation) {
121 return true;
122 } else {
123 return TestStorageSecurityIs(wifi_service, storage_security);
124 }
125 }
126};
127
Chris Masone34af2182011-08-22 11:59:36 -0700128TEST_F(WiFiServiceTest, StorageId) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800129 vector<uint8_t> ssid(5);
Chris Masone34af2182011-08-22 11:59:36 -0700130 ssid.push_back(0xff);
Chris Masone9d779932011-08-25 16:33:41 -0700131
Chris Masone2176a882011-09-14 22:29:15 -0700132 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
133 dispatcher(),
Chris Masone9d779932011-08-25 16:33:41 -0700134 manager(),
mukesh agrawal6e277772011-09-29 15:04:23 -0700135 wifi(),
Chris Masone9d779932011-08-25 16:33:41 -0700136 ssid,
137 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800138 flimflam::kSecurityNone,
139 false);
Chris Masone9d779932011-08-25 16:33:41 -0700140 string id = wifi_service->GetStorageIdentifier();
Chris Masone34af2182011-08-22 11:59:36 -0700141 for (uint i = 0; i < id.length(); ++i) {
142 EXPECT_TRUE(id[i] == '_' ||
143 isxdigit(id[i]) ||
144 (isalpha(id[i]) && islower(id[i])));
145 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700146 EXPECT_TRUE(wifi_service->TechnologyIs(Technology::kWifi));
Chris Masone34af2182011-08-22 11:59:36 -0700147 size_t mac_pos = id.find(StringToLowerASCII(string(fake_mac)));
148 EXPECT_NE(mac_pos, string::npos);
149 EXPECT_NE(id.find(string(flimflam::kModeManaged), mac_pos), string::npos);
150}
151
Gaurav Shahda6218a2011-11-11 12:09:33 -0800152// Make sure the passphrase is registered as a write only property
153// by reading and comparing all string properties returned on the store.
154TEST_F(WiFiServiceTest, PassphraseWriteOnly) {
155 vector<uint8_t> ssid(5);
156 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
157 dispatcher(),
158 manager(),
159 wifi(),
160 ssid,
161 flimflam::kModeManaged,
162 flimflam::kSecurityWpa,
163 false);
164 ReadablePropertyConstIterator<string> it =
165 (wifi_service->store()).GetStringPropertiesIter();
166 for( ; !it.AtEnd(); it.Advance())
167 EXPECT_NE(it.Key(), flimflam::kPassphraseProperty);
168}
169
Thieu Lef7709452011-11-15 01:13:19 +0000170// Make sure setting the passphrase via D-Bus Service.SetProperty validates
171// the passphrase.
172TEST_F(WiFiServiceTest, PassphraseSetPropertyValidation) {
173 // We only spot check two password cases here to make sure the
174 // SetProperty code path does validation. We're not going to exhaustively
175 // test for all types of passwords.
176 vector<uint8_t> ssid(5);
177 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
178 dispatcher(),
179 manager(),
180 wifi(),
181 ssid,
182 flimflam::kModeManaged,
183 flimflam::kSecurityWep,
184 false);
185 Error error;
186 EXPECT_TRUE(wifi_service->mutable_store()->SetStringProperty(
187 flimflam::kPassphraseProperty, "0:abcde", &error));
188 EXPECT_FALSE(wifi_service->mutable_store()->SetStringProperty(
189 flimflam::kPassphraseProperty, "invalid", &error));
190 EXPECT_EQ(Error::kInvalidPassphrase, error.type());
191}
192
193TEST_F(WiFiServiceTest, PassphraseSetPropertyOpenNetwork) {
194 vector<uint8_t> ssid(5);
195 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
196 dispatcher(),
197 manager(),
198 wifi(),
199 ssid,
200 flimflam::kModeManaged,
201 flimflam::kSecurityNone,
202 false);
203 Error error;
204 EXPECT_FALSE(wifi_service->mutable_store()->SetStringProperty(
205 flimflam::kPassphraseProperty, "invalid", &error));
206 EXPECT_EQ(Error::kNotSupported, error.type());
207}
208
mukesh agrawald835b202011-10-07 15:26:47 -0700209TEST_F(WiFiServiceTest, NonUTF8SSID) {
210 vector<uint8_t> ssid;
211
212 ssid.push_back(0xff); // not a valid UTF-8 byte-sequence
213 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
214 dispatcher(),
215 manager(),
216 wifi(),
217 ssid,
218 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800219 flimflam::kSecurityNone,
220 false);
mukesh agrawald835b202011-10-07 15:26:47 -0700221 map<string, ::DBus::Variant> properties;
222 // if service doesn't propertly sanitize SSID, this will generate SIGABRT.
223 DBusAdaptor::GetProperties(wifi_service->store(), &properties, NULL);
224}
225
Gaurav Shahda6218a2011-11-11 12:09:33 -0800226MATCHER(WPASecurityArgs, "") {
227 return ContainsKey(arg, wpa_supplicant::kPropertySecurityProtocol) &&
228 ContainsKey(arg, wpa_supplicant::kPropertyPreSharedKey);
229}
230
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700231TEST_F(WiFiServiceTest, ConnectTaskWPA) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800232 vector<uint8_t> ssid(5);
mukesh agrawal6e277772011-09-29 15:04:23 -0700233 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
234 dispatcher(),
235 manager(),
236 wifi(),
237 ssid,
238 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800239 flimflam::kSecurityWpa,
240 false);
mukesh agrawal6e277772011-09-29 15:04:23 -0700241 EXPECT_CALL(*wifi(),
242 ConnectTo(wifi_service.get(), WPASecurityArgs()));
243 wifi_service->ConnectTask();
244}
245
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700246TEST_F(WiFiServiceTest, ConnectTaskRSN) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800247 vector<uint8_t> ssid(5);
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700248 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
249 dispatcher(),
250 manager(),
251 wifi(),
252 ssid,
253 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800254 flimflam::kSecurityRsn,
255 false);
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700256 EXPECT_CALL(*wifi(),
257 ConnectTo(wifi_service.get(), WPASecurityArgs()));
258 wifi_service->ConnectTask();
259}
260
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800261TEST_F(WiFiServiceTest, ConnectTaskPSK) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800262 vector<uint8_t> ssid(5);
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800263 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
264 dispatcher(),
265 manager(),
266 wifi(),
267 ssid,
268 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800269 flimflam::kSecurityPsk,
270 false);
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800271 EXPECT_CALL(*wifi(),
272 ConnectTo(wifi_service.get(), WPASecurityArgs()));
273 wifi_service->ConnectTask();
274}
275
Thieu Lef4cbda92011-11-10 23:41:24 +0000276MATCHER(WEPSecurityArgsKeyIndex0, "") {
277 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
278 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("0")) &&
279 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
280 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
281 reader().get_uint32() == 0);
282}
283
284MATCHER(WEPSecurityArgsKeyIndex1, "") {
285 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
286 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("1")) &&
287 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
288 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
289 reader().get_uint32() == 1);
290}
291
292MATCHER(WEPSecurityArgsKeyIndex2, "") {
293 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
294 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("2")) &&
295 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
296 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
297 reader().get_uint32() == 2);
298}
299
300MATCHER(WEPSecurityArgsKeyIndex3, "") {
301 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
302 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("3")) &&
303 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
304 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
305 reader().get_uint32() == 3);
306}
307
308TEST_F(WiFiServiceTest, ConnectTaskWEP) {
309 vector<uint8_t> ssid(5);
310 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
311 dispatcher(),
312 manager(),
313 wifi(),
314 ssid,
315 flimflam::kModeManaged,
316 flimflam::kSecurityWep,
317 false);
318 Error error;
319 wifi_service->SetPassphrase("0:abcdefghijklm", &error);
320 EXPECT_CALL(*wifi(),
321 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex0()));
322 wifi_service->ConnectTask();
323
324 wifi_service->SetPassphrase("abcdefghijklm", &error);
325 EXPECT_CALL(*wifi(),
326 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex0()));
327 wifi_service->ConnectTask();
328
329 wifi_service->SetPassphrase("1:abcdefghijklm", &error);
330 EXPECT_CALL(*wifi(),
331 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex1()));
332 wifi_service->ConnectTask();
333
334 wifi_service->SetPassphrase("2:abcdefghijklm", &error);
335 EXPECT_CALL(*wifi(),
336 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex2()));
337 wifi_service->ConnectTask();
338
339 wifi_service->SetPassphrase("3:abcdefghijklm", &error);
340 EXPECT_CALL(*wifi(),
341 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex3()));
342 wifi_service->ConnectTask();
343}
344
Paul Stewartd08f4432011-11-04 07:48:20 -0700345TEST_F(WiFiServiceTest, LoadHidden) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800346 vector<uint8_t> ssid(5);
Paul Stewartd08f4432011-11-04 07:48:20 -0700347 ssid.push_back(0xff);
348
349 WiFiServiceRefPtr service = new WiFiService(control_interface(),
350 dispatcher(),
351 manager(),
352 wifi(),
353 ssid,
354 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800355 flimflam::kSecurityNone,
356 false);
Paul Stewartd08f4432011-11-04 07:48:20 -0700357 ASSERT_FALSE(service->hidden_ssid_);
358 NiceMock<MockStore> mock_store;
359 const string storage_id = service->GetStorageIdentifier();
360 EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
361 .WillRepeatedly(Return(true));
362 EXPECT_CALL(mock_store, GetBool(_, _, _))
363 .WillRepeatedly(Return(false));
364 EXPECT_CALL(mock_store,
365 GetBool(StrEq(storage_id), WiFiService::kStorageHiddenSSID, _))
366 .WillRepeatedly(DoAll(SetArgumentPointee<2>(true), Return(true)));
367 EXPECT_TRUE(service->Load(&mock_store));
368 EXPECT_TRUE(service->hidden_ssid_);
369}
370
371TEST_F(WiFiServiceSecurityTest, WPAMapping) {
372 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityRsn,
373 flimflam::kSecurityPsk));
374 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityWpa,
375 flimflam::kSecurityPsk));
376 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityPsk,
377 flimflam::kSecurityPsk));
378 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityWep,
379 flimflam::kSecurityWep));
380 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityNone,
381 flimflam::kSecurityNone));
382 // TODO(pstew): 802.1x is in a NOTIMPLEMENTED block in wifi_service.cc
383 // EXPECT_TRUE(TestStorageMapping(flimflam::kSecurity8021x,
384 // flimflam::kSecurity8021x));
385}
386
387TEST_F(WiFiServiceSecurityTest, LoadMapping) {
388 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
389 flimflam::kSecurityPsk,
390 true));
391 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
392 flimflam::kSecurityRsn,
393 true));
394 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
395 flimflam::kSecurityWpa,
396 false));
397 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
398 flimflam::kSecurityPsk,
399 true));
400 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
401 flimflam::kSecurityWpa,
402 true));
403 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
404 flimflam::kSecurityRsn,
405 false));
406 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWep,
407 flimflam::kSecurityWep,
408 true));
409 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWep,
410 flimflam::kSecurityPsk,
411 false));
412}
413
Paul Stewarta41e38d2011-11-11 07:47:29 -0800414TEST_F(WiFiServiceTest, ParseStorageIdentifier) {
415 vector<uint8_t> ssid(5);
416 ssid.push_back(0xff);
417
418 WiFiServiceRefPtr service = new WiFiService(control_interface(),
419 dispatcher(),
420 manager(),
421 wifi(),
422 ssid,
423 flimflam::kModeManaged,
424 flimflam::kSecurityNone,
425 false);
426 const string storage_id = service->GetStorageIdentifier();
427 string address;
428 string mode;
429 string security;
430 EXPECT_TRUE(service->ParseStorageIdentifier(storage_id, &address, &mode,
431 &security));
432 EXPECT_EQ(StringToLowerASCII(string(fake_mac)), address);
433 EXPECT_EQ(flimflam::kModeManaged, mode);
434 EXPECT_EQ(flimflam::kSecurityNone, security);
435}
436
Chris Masone34af2182011-08-22 11:59:36 -0700437} // namespace shill