blob: 244b957bd7c404b0ace4ddb7854ebde4d4ba1a44 [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[];
mukesh agrawal29c13a12011-11-24 00:09:19 +000052 bool CheckConnectable(const std::string &security, const char *passphrase) {
53 Error error;
54 vector<uint8_t> ssid(1, 'a');
55 WiFiServiceRefPtr service = new WiFiService(control_interface(),
56 dispatcher(),
57 manager(),
58 wifi(),
59 ssid,
60 flimflam::kModeManaged,
61 security,
62 false);
63 if (passphrase)
64 service->SetPassphrase(passphrase, &error);
65 return service->connectable();
66 }
mukesh agrawal6e277772011-09-29 15:04:23 -070067 scoped_refptr<MockWiFi> wifi() { return wifi_; }
68
69 private:
70 scoped_refptr<MockWiFi> wifi_;
Chris Masone34af2182011-08-22 11:59:36 -070071};
72
mukesh agrawal6e277772011-09-29 15:04:23 -070073// static
74const char WiFiServiceTest::fake_mac[] = "AaBBcCDDeeFF";
75
Paul Stewartd08f4432011-11-04 07:48:20 -070076class WiFiServiceSecurityTest : public WiFiServiceTest {
77 public:
78 WiFiServiceRefPtr CreateServiceWithSecurity(const string &security) {
Gaurav Shahda6218a2011-11-11 12:09:33 -080079 vector<uint8_t> ssid(5);
Paul Stewartd08f4432011-11-04 07:48:20 -070080 ssid.push_back(0xff);
81
82 return new WiFiService(control_interface(),
83 dispatcher(),
84 manager(),
85 wifi(),
86 ssid,
87 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -080088 security,
89 false);
Paul Stewartd08f4432011-11-04 07:48:20 -070090 }
91
92 bool TestStorageSecurityIs(WiFiServiceRefPtr wifi_service,
93 const string &security) {
94 string id = wifi_service->GetStorageIdentifier();
95 size_t mac_pos = id.find(StringToLowerASCII(string(fake_mac)));
96 EXPECT_NE(mac_pos, string::npos);
97 size_t mode_pos = id.find(string(flimflam::kModeManaged), mac_pos);
98 EXPECT_NE(mode_pos, string::npos);
99 return id.find(string(security), mode_pos) != string::npos;
100 }
101
102 // Test that a service that is created with security |from_security|
103 // gets by default a storage identifier with |to_security| as its
104 // security component.
105 bool TestStorageMapping(const string &from_security,
106 const string &to_security) {
107 WiFiServiceRefPtr wifi_service = CreateServiceWithSecurity(from_security);
108 return TestStorageSecurityIs(wifi_service, to_security);
109 }
110
111 // Test whether a service of type |service_security| can load from a
112 // storage interface containing an entry for |storage_security|.
113 // Make sure the result meets |expectation|. If |expectation| is
114 // true, also make sure the service storage identifier changes to
115 // match |storage_security|.
116 bool TestLoadMapping(const string &service_security,
117 const string &storage_security,
118 bool expectation) {
119 WiFiServiceRefPtr wifi_service =
120 CreateServiceWithSecurity(service_security);
121 NiceMock<MockStore> mock_store;
122 const string storage_id =
123 wifi_service->GetStorageIdentifierForSecurity(storage_security);
124 EXPECT_CALL(mock_store, ContainsGroup(_))
125 .WillRepeatedly(Return(false));
126 EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
127 .WillRepeatedly(Return(true));
128 bool is_loadable = wifi_service->IsLoadableFrom(&mock_store);
129 EXPECT_EQ(expectation, is_loadable);
130 bool is_loaded = wifi_service->Load(&mock_store);
131 EXPECT_EQ(expectation, is_loaded);
132
133 if (expectation != is_loadable || expectation != is_loaded) {
134 return false;
135 } else if (!expectation) {
136 return true;
137 } else {
138 return TestStorageSecurityIs(wifi_service, storage_security);
139 }
140 }
141};
142
Chris Masone34af2182011-08-22 11:59:36 -0700143TEST_F(WiFiServiceTest, StorageId) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800144 vector<uint8_t> ssid(5);
Chris Masone34af2182011-08-22 11:59:36 -0700145 ssid.push_back(0xff);
Chris Masone9d779932011-08-25 16:33:41 -0700146
Chris Masone2176a882011-09-14 22:29:15 -0700147 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
148 dispatcher(),
Chris Masone9d779932011-08-25 16:33:41 -0700149 manager(),
mukesh agrawal6e277772011-09-29 15:04:23 -0700150 wifi(),
Chris Masone9d779932011-08-25 16:33:41 -0700151 ssid,
152 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800153 flimflam::kSecurityNone,
154 false);
Chris Masone9d779932011-08-25 16:33:41 -0700155 string id = wifi_service->GetStorageIdentifier();
Chris Masone34af2182011-08-22 11:59:36 -0700156 for (uint i = 0; i < id.length(); ++i) {
157 EXPECT_TRUE(id[i] == '_' ||
158 isxdigit(id[i]) ||
159 (isalpha(id[i]) && islower(id[i])));
160 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700161 EXPECT_TRUE(wifi_service->TechnologyIs(Technology::kWifi));
Chris Masone34af2182011-08-22 11:59:36 -0700162 size_t mac_pos = id.find(StringToLowerASCII(string(fake_mac)));
163 EXPECT_NE(mac_pos, string::npos);
164 EXPECT_NE(id.find(string(flimflam::kModeManaged), mac_pos), string::npos);
165}
166
Gaurav Shahda6218a2011-11-11 12:09:33 -0800167// Make sure the passphrase is registered as a write only property
168// by reading and comparing all string properties returned on the store.
169TEST_F(WiFiServiceTest, PassphraseWriteOnly) {
170 vector<uint8_t> ssid(5);
171 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
172 dispatcher(),
173 manager(),
174 wifi(),
175 ssid,
176 flimflam::kModeManaged,
177 flimflam::kSecurityWpa,
178 false);
179 ReadablePropertyConstIterator<string> it =
180 (wifi_service->store()).GetStringPropertiesIter();
181 for( ; !it.AtEnd(); it.Advance())
182 EXPECT_NE(it.Key(), flimflam::kPassphraseProperty);
183}
184
Thieu Lef7709452011-11-15 01:13:19 +0000185// Make sure setting the passphrase via D-Bus Service.SetProperty validates
186// the passphrase.
187TEST_F(WiFiServiceTest, PassphraseSetPropertyValidation) {
188 // We only spot check two password cases here to make sure the
189 // SetProperty code path does validation. We're not going to exhaustively
190 // test for all types of passwords.
191 vector<uint8_t> ssid(5);
192 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
193 dispatcher(),
194 manager(),
195 wifi(),
196 ssid,
197 flimflam::kModeManaged,
198 flimflam::kSecurityWep,
199 false);
200 Error error;
201 EXPECT_TRUE(wifi_service->mutable_store()->SetStringProperty(
202 flimflam::kPassphraseProperty, "0:abcde", &error));
203 EXPECT_FALSE(wifi_service->mutable_store()->SetStringProperty(
204 flimflam::kPassphraseProperty, "invalid", &error));
205 EXPECT_EQ(Error::kInvalidPassphrase, error.type());
206}
207
208TEST_F(WiFiServiceTest, PassphraseSetPropertyOpenNetwork) {
209 vector<uint8_t> ssid(5);
210 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
211 dispatcher(),
212 manager(),
213 wifi(),
214 ssid,
215 flimflam::kModeManaged,
216 flimflam::kSecurityNone,
217 false);
218 Error error;
219 EXPECT_FALSE(wifi_service->mutable_store()->SetStringProperty(
220 flimflam::kPassphraseProperty, "invalid", &error));
221 EXPECT_EQ(Error::kNotSupported, error.type());
222}
223
mukesh agrawald835b202011-10-07 15:26:47 -0700224TEST_F(WiFiServiceTest, NonUTF8SSID) {
225 vector<uint8_t> ssid;
226
227 ssid.push_back(0xff); // not a valid UTF-8 byte-sequence
228 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
229 dispatcher(),
230 manager(),
231 wifi(),
232 ssid,
233 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800234 flimflam::kSecurityNone,
235 false);
mukesh agrawald835b202011-10-07 15:26:47 -0700236 map<string, ::DBus::Variant> properties;
237 // if service doesn't propertly sanitize SSID, this will generate SIGABRT.
238 DBusAdaptor::GetProperties(wifi_service->store(), &properties, NULL);
239}
240
Gaurav Shahda6218a2011-11-11 12:09:33 -0800241MATCHER(WPASecurityArgs, "") {
242 return ContainsKey(arg, wpa_supplicant::kPropertySecurityProtocol) &&
243 ContainsKey(arg, wpa_supplicant::kPropertyPreSharedKey);
244}
245
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700246TEST_F(WiFiServiceTest, ConnectTaskWPA) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800247 vector<uint8_t> ssid(5);
mukesh agrawal6e277772011-09-29 15:04:23 -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::kSecurityWpa,
255 false);
mukesh agrawal6e277772011-09-29 15:04:23 -0700256 EXPECT_CALL(*wifi(),
257 ConnectTo(wifi_service.get(), WPASecurityArgs()));
258 wifi_service->ConnectTask();
259}
260
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700261TEST_F(WiFiServiceTest, ConnectTaskRSN) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800262 vector<uint8_t> ssid(5);
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700263 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::kSecurityRsn,
270 false);
mukesh agrawalf2fd7452011-10-03 16:38:47 -0700271 EXPECT_CALL(*wifi(),
272 ConnectTo(wifi_service.get(), WPASecurityArgs()));
273 wifi_service->ConnectTask();
274}
275
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800276TEST_F(WiFiServiceTest, ConnectTaskPSK) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800277 vector<uint8_t> ssid(5);
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800278 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
279 dispatcher(),
280 manager(),
281 wifi(),
282 ssid,
283 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800284 flimflam::kSecurityPsk,
285 false);
Gaurav Shahf8721ee2011-11-07 09:12:46 -0800286 EXPECT_CALL(*wifi(),
287 ConnectTo(wifi_service.get(), WPASecurityArgs()));
288 wifi_service->ConnectTask();
289}
290
Thieu Lef4cbda92011-11-10 23:41:24 +0000291MATCHER(WEPSecurityArgsKeyIndex0, "") {
292 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
293 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("0")) &&
294 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
295 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
296 reader().get_uint32() == 0);
297}
298
299MATCHER(WEPSecurityArgsKeyIndex1, "") {
300 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
301 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("1")) &&
302 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
303 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
304 reader().get_uint32() == 1);
305}
306
307MATCHER(WEPSecurityArgsKeyIndex2, "") {
308 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
309 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("2")) &&
310 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
311 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
312 reader().get_uint32() == 2);
313}
314
315MATCHER(WEPSecurityArgsKeyIndex3, "") {
316 return ContainsKey(arg, wpa_supplicant::kPropertyAuthAlg) &&
317 ContainsKey(arg, wpa_supplicant::kPropertyWEPKey + std::string("3")) &&
318 ContainsKey(arg, wpa_supplicant::kPropertyWEPTxKeyIndex) &&
319 (arg.find(wpa_supplicant::kPropertyWEPTxKeyIndex)->second.
320 reader().get_uint32() == 3);
321}
322
323TEST_F(WiFiServiceTest, ConnectTaskWEP) {
324 vector<uint8_t> ssid(5);
325 WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
326 dispatcher(),
327 manager(),
328 wifi(),
329 ssid,
330 flimflam::kModeManaged,
331 flimflam::kSecurityWep,
332 false);
333 Error error;
334 wifi_service->SetPassphrase("0:abcdefghijklm", &error);
335 EXPECT_CALL(*wifi(),
336 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex0()));
337 wifi_service->ConnectTask();
338
339 wifi_service->SetPassphrase("abcdefghijklm", &error);
340 EXPECT_CALL(*wifi(),
341 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex0()));
342 wifi_service->ConnectTask();
343
344 wifi_service->SetPassphrase("1:abcdefghijklm", &error);
345 EXPECT_CALL(*wifi(),
346 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex1()));
347 wifi_service->ConnectTask();
348
349 wifi_service->SetPassphrase("2:abcdefghijklm", &error);
350 EXPECT_CALL(*wifi(),
351 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex2()));
352 wifi_service->ConnectTask();
353
354 wifi_service->SetPassphrase("3:abcdefghijklm", &error);
355 EXPECT_CALL(*wifi(),
356 ConnectTo(wifi_service.get(), WEPSecurityArgsKeyIndex3()));
357 wifi_service->ConnectTask();
358}
359
Paul Stewartd08f4432011-11-04 07:48:20 -0700360TEST_F(WiFiServiceTest, LoadHidden) {
Gaurav Shahda6218a2011-11-11 12:09:33 -0800361 vector<uint8_t> ssid(5);
Paul Stewartd08f4432011-11-04 07:48:20 -0700362 ssid.push_back(0xff);
363
364 WiFiServiceRefPtr service = new WiFiService(control_interface(),
365 dispatcher(),
366 manager(),
367 wifi(),
368 ssid,
369 flimflam::kModeManaged,
Paul Stewartced6a0b2011-11-08 15:32:04 -0800370 flimflam::kSecurityNone,
371 false);
Paul Stewartd08f4432011-11-04 07:48:20 -0700372 ASSERT_FALSE(service->hidden_ssid_);
373 NiceMock<MockStore> mock_store;
374 const string storage_id = service->GetStorageIdentifier();
375 EXPECT_CALL(mock_store, ContainsGroup(StrEq(storage_id)))
376 .WillRepeatedly(Return(true));
377 EXPECT_CALL(mock_store, GetBool(_, _, _))
378 .WillRepeatedly(Return(false));
379 EXPECT_CALL(mock_store,
380 GetBool(StrEq(storage_id), WiFiService::kStorageHiddenSSID, _))
381 .WillRepeatedly(DoAll(SetArgumentPointee<2>(true), Return(true)));
382 EXPECT_TRUE(service->Load(&mock_store));
383 EXPECT_TRUE(service->hidden_ssid_);
384}
385
386TEST_F(WiFiServiceSecurityTest, WPAMapping) {
387 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityRsn,
388 flimflam::kSecurityPsk));
389 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityWpa,
390 flimflam::kSecurityPsk));
391 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityPsk,
392 flimflam::kSecurityPsk));
393 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityWep,
394 flimflam::kSecurityWep));
395 EXPECT_TRUE(TestStorageMapping(flimflam::kSecurityNone,
396 flimflam::kSecurityNone));
397 // TODO(pstew): 802.1x is in a NOTIMPLEMENTED block in wifi_service.cc
398 // EXPECT_TRUE(TestStorageMapping(flimflam::kSecurity8021x,
399 // flimflam::kSecurity8021x));
400}
401
402TEST_F(WiFiServiceSecurityTest, LoadMapping) {
403 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
404 flimflam::kSecurityPsk,
405 true));
406 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
407 flimflam::kSecurityRsn,
408 true));
409 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityRsn,
410 flimflam::kSecurityWpa,
411 false));
412 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
413 flimflam::kSecurityPsk,
414 true));
415 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
416 flimflam::kSecurityWpa,
417 true));
418 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWpa,
419 flimflam::kSecurityRsn,
420 false));
421 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWep,
422 flimflam::kSecurityWep,
423 true));
424 EXPECT_TRUE(TestLoadMapping(flimflam::kSecurityWep,
425 flimflam::kSecurityPsk,
426 false));
427}
428
Paul Stewarta41e38d2011-11-11 07:47:29 -0800429TEST_F(WiFiServiceTest, ParseStorageIdentifier) {
430 vector<uint8_t> ssid(5);
431 ssid.push_back(0xff);
432
433 WiFiServiceRefPtr service = new WiFiService(control_interface(),
434 dispatcher(),
435 manager(),
436 wifi(),
437 ssid,
438 flimflam::kModeManaged,
439 flimflam::kSecurityNone,
440 false);
441 const string storage_id = service->GetStorageIdentifier();
442 string address;
443 string mode;
444 string security;
445 EXPECT_TRUE(service->ParseStorageIdentifier(storage_id, &address, &mode,
446 &security));
447 EXPECT_EQ(StringToLowerASCII(string(fake_mac)), address);
448 EXPECT_EQ(flimflam::kModeManaged, mode);
449 EXPECT_EQ(flimflam::kSecurityNone, security);
450}
451
mukesh agrawal29c13a12011-11-24 00:09:19 +0000452TEST_F(WiFiServiceTest, Connectable) {
453 // Open network should be connectable.
454 EXPECT_TRUE(CheckConnectable(flimflam::kSecurityNone, NULL));
455
456 // Open network should remain connectable if we try to set a password on it.
457 EXPECT_TRUE(CheckConnectable(flimflam::kSecurityNone, "abcde"));
458
459 // WEP network with passphrase set should be connectable.
460 EXPECT_TRUE(CheckConnectable(flimflam::kSecurityWep, "abcde"));
461
462 // WEP network without passphrase set should NOT be connectable.
463 EXPECT_FALSE(CheckConnectable(flimflam::kSecurityWep, NULL));
464
465 // A bad passphrase should not make a WEP network connectable.
466 EXPECT_FALSE(CheckConnectable(flimflam::kSecurityWep, "a"));
467
468 // Similar to WEP, for WPA.
469 EXPECT_TRUE(CheckConnectable(flimflam::kSecurityWpa, "abcdefgh"));
470 EXPECT_FALSE(CheckConnectable(flimflam::kSecurityWpa, NULL));
471 EXPECT_FALSE(CheckConnectable(flimflam::kSecurityWpa, "a"));
472
473 // Unconfigured 802.1x should NOT be connectable.
474 EXPECT_FALSE(CheckConnectable(flimflam::kSecurity8021x, NULL));
475}
476
Chris Masone34af2182011-08-22 11:59:36 -0700477} // namespace shill