blob: d12d271064e2616d13457f64872983b9c388d1c8 [file] [log] [blame]
Paul Stewartb50f0b92011-05-16 16:31:42 -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
Chris Masone2b105542011-06-22 10:58:09 -07005#include "shill/wifi.h"
6
Paul Stewartb50f0b92011-05-16 16:31:42 -07007#include <time.h>
8#include <stdio.h>
mukesh agrawalc7426a42011-06-03 13:04:28 -07009#include <string.h>
mukesh agrawalf2f68a52011-09-01 12:15:48 -070010#include <netinet/ether.h>
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -070011#include <linux/if.h> // Needs definitions from netinet/ether.h
Paul Stewartb50f0b92011-05-16 16:31:42 -070012
mukesh agrawalab87ea42011-05-18 11:44:49 -070013#include <map>
Paul Stewartb50f0b92011-05-16 16:31:42 -070014#include <string>
mukesh agrawalab87ea42011-05-18 11:44:49 -070015#include <vector>
Paul Stewartb50f0b92011-05-16 16:31:42 -070016
17#include <base/logging.h>
mukesh agrawal7a4e4002011-09-06 11:26:05 -070018#include <base/string_number_conversions.h>
19#include <base/string_util.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070020#include <chromeos/dbus/service_constants.h>
Paul Stewartb50f0b92011-05-16 16:31:42 -070021
22#include "shill/control_interface.h"
23#include "shill/device.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070024#include "shill/error.h"
25#include "shill/key_value_store.h"
26#include "shill/ieee80211.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070027#include "shill/manager.h"
28#include "shill/profile.h"
Darin Petkovd1967262011-07-18 14:55:18 -070029#include "shill/proxy_factory.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070030#include "shill/shill_event.h"
mukesh agrawalaf571952011-07-14 14:31:12 -070031#include "shill/supplicant_interface_proxy_interface.h"
32#include "shill/supplicant_process_proxy_interface.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070033#include "shill/wifi_endpoint.h"
34#include "shill/wifi_service.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070035#include "shill/wpa_supplicant.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070036
mukesh agrawal7a4e4002011-09-06 11:26:05 -070037using std::map;
mukesh agrawalab87ea42011-05-18 11:44:49 -070038using std::string;
mukesh agrawal7a4e4002011-09-06 11:26:05 -070039using std::vector;
mukesh agrawalab87ea42011-05-18 11:44:49 -070040
Paul Stewartb50f0b92011-05-16 16:31:42 -070041namespace shill {
mukesh agrawal7a4e4002011-09-06 11:26:05 -070042
43// statics
44//
45// Note that WiFi generates some manager-level errors, because it implements
46// the Manager.GetWiFiService flimflam API. The API is implemented here,
47// rather than in manager, to keep WiFi-specific logic in the right place.
48const char WiFi::kManagerErrorPassphraseRequired[] = "must specify passphrase";
49const char WiFi::kManagerErrorSSIDRequired[] = "must specify SSID";
50const char WiFi::kManagerErrorSSIDTooLong[] = "SSID is too long";
51const char WiFi::kManagerErrorSSIDTooShort[] = "SSID is too short";
52const char WiFi::kManagerErrorTypeRequired[] = "must specify service type";
53const char WiFi::kManagerErrorUnsupportedSecurityMode[] =
54 "security mode is unsupported";
55const char WiFi::kManagerErrorUnsupportedServiceType[] =
56 "service type is unsupported";
57const char WiFi::kManagerErrorUnsupportedServiceMode[] =
58 "service mode is unsupported";
mukesh agrawalb54601c2011-06-07 17:39:22 -070059
mukesh agrawalab87ea42011-05-18 11:44:49 -070060// NB: we assume supplicant is already running. [quiche.20110518]
Paul Stewartb50f0b92011-05-16 16:31:42 -070061WiFi::WiFi(ControlInterface *control_interface,
62 EventDispatcher *dispatcher,
Paul Stewartf1ce5d22011-05-19 13:10:20 -070063 Manager *manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070064 const string& link,
Chris Masone626719f2011-08-18 16:58:48 -070065 const std::string &address,
Paul Stewartb50f0b92011-05-16 16:31:42 -070066 int interface_index)
Chris Masonea82b7112011-05-25 15:16:29 -070067 : Device(control_interface,
68 dispatcher,
69 manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070070 link,
Chris Masone626719f2011-08-18 16:58:48 -070071 address,
mukesh agrawalab87ea42011-05-18 11:44:49 -070072 interface_index),
mukesh agrawalb54601c2011-06-07 17:39:22 -070073 task_factory_(this),
Chris Masone853b81b2011-06-24 14:11:41 -070074 bgscan_short_interval_(0),
75 bgscan_signal_threshold_(0),
76 scan_pending_(false),
mukesh agrawalf2f68a52011-09-01 12:15:48 -070077 scan_interval_(0),
78 link_up_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -070079 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -070080 store->RegisterString(flimflam::kBgscanMethodProperty, &bgscan_method_);
81 store->RegisterUint16(flimflam::kBgscanShortIntervalProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070082 &bgscan_short_interval_);
Paul Stewartac4ac002011-08-26 12:04:26 -070083 store->RegisterInt32(flimflam::kBgscanSignalThresholdProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070084 &bgscan_signal_threshold_);
85
Chris Masoneb925cc82011-06-22 15:39:57 -070086 // TODO(quiche): Decide if scan_pending_ is close enough to
87 // "currently scanning" that we don't care, or if we want to track
88 // scan pending/currently scanning/no scan scheduled as a tri-state
89 // kind of thing.
Paul Stewartac4ac002011-08-26 12:04:26 -070090 store->RegisterConstBool(flimflam::kScanningProperty, &scan_pending_);
91 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
92 VLOG(2) << "WiFi device " << link_name() << " initialized.";
Paul Stewartb50f0b92011-05-16 16:31:42 -070093}
94
mukesh agrawalaf571952011-07-14 14:31:12 -070095WiFi::~WiFi() {}
Paul Stewartb50f0b92011-05-16 16:31:42 -070096
mukesh agrawalab87ea42011-05-18 11:44:49 -070097void WiFi::Start() {
mukesh agrawalab87ea42011-05-18 11:44:49 -070098 ::DBus::Path interface_path;
99
mukesh agrawalaf571952011-07-14 14:31:12 -0700100 supplicant_process_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -0700101 ProxyFactory::factory()->CreateSupplicantProcessProxy(
mukesh agrawal6e277772011-09-29 15:04:23 -0700102 wpa_supplicant::kDBusPath, wpa_supplicant::kDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -0700103 try {
104 std::map<string, DBus::Variant> create_interface_args;
105 create_interface_args["Ifname"].writer().
Paul Stewartac4ac002011-08-26 12:04:26 -0700106 append_string(link_name().c_str());
mukesh agrawalc7426a42011-06-03 13:04:28 -0700107 create_interface_args["Driver"].writer().
mukesh agrawal6e277772011-09-29 15:04:23 -0700108 append_string(wpa_supplicant::kDriverNL80211);
mukesh agrawalc7426a42011-06-03 13:04:28 -0700109 // TODO(quiche) create_interface_args["ConfigFile"].writer().append_string
110 // (file with pkcs config info)
111 interface_path =
112 supplicant_process_proxy_->CreateInterface(create_interface_args);
113 } catch (const DBus::Error e) { // NOLINT
mukesh agrawal6e277772011-09-29 15:04:23 -0700114 if (!strcmp(e.name(), wpa_supplicant::kErrorInterfaceExists)) {
mukesh agrawalc7426a42011-06-03 13:04:28 -0700115 interface_path =
Paul Stewartac4ac002011-08-26 12:04:26 -0700116 supplicant_process_proxy_->GetInterface(link_name());
mukesh agrawalb54601c2011-06-07 17:39:22 -0700117 // XXX crash here, if device missing?
mukesh agrawalc7426a42011-06-03 13:04:28 -0700118 } else {
119 // XXX
120 }
121 }
122
mukesh agrawalab87ea42011-05-18 11:44:49 -0700123 supplicant_interface_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -0700124 ProxyFactory::factory()->CreateSupplicantInterfaceProxy(
mukesh agrawal6e277772011-09-29 15:04:23 -0700125 this, interface_path, wpa_supplicant::kDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -0700126
mukesh agrawalab87ea42011-05-18 11:44:49 -0700127 // TODO(quiche) set ApScan=1 and BSSExpireAge=190, like flimflam does?
mukesh agrawalc7426a42011-06-03 13:04:28 -0700128
129 // clear out any networks that might previously have been configured
130 // for this interface.
131 supplicant_interface_proxy_->RemoveAllNetworks();
132
133 // flush interface's BSS cache, so that we get BSSAdded signals for
134 // all BSSes (not just new ones since the last scan).
135 supplicant_interface_proxy_->FlushBSS(0);
136
Darin Petkovc0865312011-09-16 15:31:20 -0700137 Scan(NULL);
mukesh agrawalab87ea42011-05-18 11:44:49 -0700138 Device::Start();
139}
140
mukesh agrawalab87ea42011-05-18 11:44:49 -0700141void WiFi::Stop() {
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700142 VLOG(2) << "WiFi " << link_name() << " stopping.";
mukesh agrawal31950242011-07-14 11:53:38 -0700143 // TODO(quiche): remove interface from supplicant
144 supplicant_interface_proxy_.reset(); // breaks a reference cycle
145 supplicant_process_proxy_.reset();
146 endpoint_by_bssid_.clear();
147 service_by_private_id_.clear(); // breaks reference cycles
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700148
149 for (std::vector<ServiceRefPtr>::const_iterator it = services()->begin();
150 it != services()->end();
151 ++it) {
152 manager()->DeregisterService(*it);
153 }
154 services()->clear(); // breaks reference cycles
155
mukesh agrawalab87ea42011-05-18 11:44:49 -0700156 Device::Stop();
mukesh agrawal31950242011-07-14 11:53:38 -0700157 // XXX anything else to do?
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700158
159 VLOG(3) << "WiFi " << link_name() << " task_factory_ "
160 << (task_factory_.empty() ? "is empty." : "is not empty.");
161 VLOG(3) << "WiFi " << link_name() << " supplicant_process_proxy_ "
162 << (supplicant_process_proxy_.get() ? "is set." : "is not set.");
163 VLOG(3) << "WiFi " << link_name() << " supplicant_interface_proxy_ "
164 << (supplicant_interface_proxy_.get() ? "is set." : "is not set.");
165 VLOG(3) << "WiFi " << link_name() << " has " << endpoint_by_bssid_.size()
166 << " EndpointMap entries.";
167 VLOG(3) << "WiFi " << link_name() << " has " << service_by_private_id_.size()
168 << " ServiceMap entries.";
mukesh agrawalab87ea42011-05-18 11:44:49 -0700169}
170
mukesh agrawal1830fa12011-09-26 14:31:40 -0700171void WiFi::Scan(Error */*error*/) {
mukesh agrawal32399322011-09-01 10:53:43 -0700172 LOG(INFO) << __func__;
173
174 // needs to send a D-Bus message, but may be called from D-Bus
175 // signal handler context (via Manager::RequestScan). so defer work
176 // to event loop.
177 dispatcher()->PostTask(
178 task_factory_.NewRunnableMethod(&WiFi::ScanTask));
179}
180
Paul Stewartfdd16072011-09-16 12:41:35 -0700181bool WiFi::TechnologyIs(const Technology::Identifier type) const {
182 return type == Technology::kWifi;
Paul Stewartb50f0b92011-05-16 16:31:42 -0700183}
184
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700185void WiFi::LinkEvent(unsigned int flags, unsigned int change) {
186 // TODO(quiche): figure out how to relate these events to supplicant
187 // events. e.g., may be we can ignore LinkEvent, in favor of events
188 // from SupplicantInterfaceProxy?
189 Device::LinkEvent(flags, change);
190 if ((flags & IFF_LOWER_UP) != 0 && !link_up_) {
191 LOG(INFO) << link_name() << " is up; should start L3!";
192 link_up_ = true;
193 if (AcquireDHCPConfig()) {
194 SetServiceState(Service::kStateConfiguring);
195 } else {
196 LOG(ERROR) << "Unable to acquire DHCP config.";
197 }
198 } else if ((flags & IFF_LOWER_UP) == 0 && link_up_) {
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700199 LOG(INFO) << link_name() << " is down";
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700200 link_up_ = false;
201 // TODO(quiche): attempt to reconnect to current SSID, another SSID,
202 // or initiate a scan.
203 }
204}
205
mukesh agrawalb54601c2011-06-07 17:39:22 -0700206void WiFi::BSSAdded(
mukesh agrawal1830fa12011-09-26 14:31:40 -0700207 const ::DBus::Path &/*BSS*/,
mukesh agrawalb54601c2011-06-07 17:39:22 -0700208 const std::map<string, ::DBus::Variant> &properties) {
209 // TODO(quiche): write test to verify correct behavior in the case
210 // where we get multiple BSSAdded events for a single endpoint.
211 // (old Endpoint's refcount should fall to zero, and old Endpoint
212 // should be destroyed)
213 //
214 // note: we assume that BSSIDs are unique across endpoints. this
215 // means that if an AP reuses the same BSSID for multiple SSIDs, we
216 // lose.
217 WiFiEndpointRefPtr endpoint(new WiFiEndpoint(properties));
218 endpoint_by_bssid_[endpoint->bssid_hex()] = endpoint;
219}
220
221void WiFi::ScanDone() {
222 LOG(INFO) << __func__;
223
224 // defer handling of scan result processing, because that processing
225 // may require the the registration of new D-Bus objects. and such
226 // registration can't be done in the context of a D-Bus signal
227 // handler.
Paul Stewartac4ac002011-08-26 12:04:26 -0700228 dispatcher()->PostTask(
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700229 task_factory_.NewRunnableMethod(&WiFi::ScanDoneTask));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700230}
231
mukesh agrawal6e277772011-09-29 15:04:23 -0700232void WiFi::ConnectTo(WiFiService *service,
233 const map<string, DBus::Variant> &service_params) {
mukesh agrawal445e72c2011-06-22 11:13:50 -0700234 DBus::Path network_path;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700235
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700236 // TODO(quiche): handle cases where already connected
mukesh agrawal32399322011-09-01 10:53:43 -0700237
mukesh agrawal6e277772011-09-29 15:04:23 -0700238 // TODO(quiche): set scan_ssid=1 in service_params, like flimflam does?
239 try {
240 network_path =
241 supplicant_interface_proxy_->AddNetwork(service_params);
242 } catch (const DBus::Error e) { // NOLINT
243 LOG(ERROR) << "exception while adding network: " << e.what();
244 return;
245 }
mukesh agrawal445e72c2011-06-22 11:13:50 -0700246
mukesh agrawal445e72c2011-06-22 11:13:50 -0700247 supplicant_interface_proxy_->SelectNetwork(network_path);
248 // XXX add to favorite networks list?
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700249
250 // SelectService here (instead of in LinkEvent, like Ethernet), so
251 // that, if we fail to bring up L2, we can attribute failure correctly.
252 //
253 // TODO(quiche): when we add code for dealing with connection failures,
254 // reconsider if this is the right place to change the selected service.
255 // see discussion in crosbug.com/20191.
256 SelectService(service);
mukesh agrawalb54601c2011-06-07 17:39:22 -0700257}
258
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700259void WiFi::ScanDoneTask() {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700260 LOG(INFO) << __func__;
261
262 scan_pending_ = false;
263
264 // TODO(quiche): group endpoints into services, instead of creating
265 // a service for every endpoint.
266 for (EndpointMap::iterator i(endpoint_by_bssid_.begin());
267 i != endpoint_by_bssid_.end(); ++i) {
268 const WiFiEndpoint &endpoint(*(i->second));
269 string service_id_private;
270
271 service_id_private =
272 endpoint.ssid_hex() + "_" + endpoint.bssid_hex();
273 if (service_by_private_id_.find(service_id_private) ==
274 service_by_private_id_.end()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700275 LOG(INFO) << "found new endpoint. "
276 << "ssid: " << endpoint.ssid_string() << ", "
277 << "bssid: " << endpoint.bssid_string() << ", "
mukesh agrawal6e277772011-09-29 15:04:23 -0700278 << "signal: " << endpoint.signal_strength() << ", "
279 << "security: " << endpoint.security_mode();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700280
mukesh agrawal31950242011-07-14 11:53:38 -0700281 WiFiServiceRefPtr service(
Paul Stewartac4ac002011-08-26 12:04:26 -0700282 new WiFiService(control_interface(),
283 dispatcher(),
284 manager(),
Chris Masone7aa5f902011-07-11 11:13:35 -0700285 this,
Chris Masone7aa5f902011-07-11 11:13:35 -0700286 endpoint.ssid(),
287 endpoint.network_mode(),
mukesh agrawal6e277772011-09-29 15:04:23 -0700288 endpoint.security_mode()));
Paul Stewartac4ac002011-08-26 12:04:26 -0700289 services()->push_back(service);
mukesh agrawalb54601c2011-06-07 17:39:22 -0700290 service_by_private_id_[service_id_private] = service;
mukesh agrawal32399322011-09-01 10:53:43 -0700291 manager()->RegisterService(service);
mukesh agrawal51a7e932011-07-27 16:18:26 -0700292
293 LOG(INFO) << "new service " << service->GetRpcIdentifier();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700294 }
295 }
296
mukesh agrawalb54601c2011-06-07 17:39:22 -0700297 // TODO(quiche): unregister removed services from manager
298}
299
mukesh agrawal32399322011-09-01 10:53:43 -0700300void WiFi::ScanTask() {
301 VLOG(2) << "WiFi " << link_name() << " scan requested.";
302 std::map<string, DBus::Variant> scan_args;
mukesh agrawal6e277772011-09-29 15:04:23 -0700303 scan_args[wpa_supplicant::kPropertyScanType].writer().
304 append_string(wpa_supplicant::kScanTypeActive);
mukesh agrawal32399322011-09-01 10:53:43 -0700305 // TODO(quiche) indicate scanning in UI
306 supplicant_interface_proxy_->Scan(scan_args);
307 scan_pending_ = true;
308}
309
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700310// used by manager, via static WiFi::GetService method
311WiFiServiceRefPtr WiFi::GetService(const KeyValueStore &args, Error *error) {
312 if (!args.ContainsString(flimflam::kTypeProperty)) {
313 error->Populate(Error::kInvalidArguments, kManagerErrorTypeRequired);
314 return NULL;
315 }
316
317 if (args.GetString(flimflam::kTypeProperty) != flimflam::kTypeWifi) {
318 error->Populate(Error::kNotSupported, kManagerErrorUnsupportedServiceType);
319 return NULL;
320 }
321
322 if (args.ContainsString(flimflam::kModeProperty) &&
323 args.GetString(flimflam::kModeProperty) !=
324 flimflam::kModeManaged) {
325 error->Populate(Error::kNotSupported, kManagerErrorUnsupportedServiceMode);
326 return NULL;
327 }
328
329 if (!args.ContainsString(flimflam::kSSIDProperty)) {
330 error->Populate(Error::kInvalidArguments, kManagerErrorSSIDRequired);
331 return NULL;
332 }
333
334 string ssid = args.GetString(flimflam::kSSIDProperty);
335 if (ssid.length() < 1) {
336 error->Populate(Error::kInvalidNetworkName, kManagerErrorSSIDTooShort);
337 return NULL;
338 }
339
340 if (ssid.length() > IEEE_80211::kMaxSSIDLen) {
341 error->Populate(Error::kInvalidNetworkName, kManagerErrorSSIDTooLong);
342 return NULL;
343 }
344
345 string security_method;
346 if (args.ContainsString(flimflam::kSecurityProperty)) {
347 security_method = args.GetString(flimflam::kSecurityProperty);
348 } else {
349 security_method = flimflam::kSecurityNone;
350 }
351
352 if (security_method != flimflam::kSecurityNone &&
353 security_method != flimflam::kSecurityWep &&
354 security_method != flimflam::kSecurityPsk &&
355 security_method != flimflam::kSecurityWpa &&
356 security_method != flimflam::kSecurityRsn &&
357 security_method != flimflam::kSecurity8021x) {
358 error->Populate(Error::kNotSupported,
359 kManagerErrorUnsupportedSecurityMode);
360 return NULL;
361 }
362
363 if ((security_method == flimflam::kSecurityWep ||
364 security_method == flimflam::kSecurityPsk ||
365 security_method == flimflam::kSecurityWpa ||
366 security_method == flimflam::kSecurityRsn) &&
367 !args.ContainsString(flimflam::kPassphraseProperty)) {
368 error->Populate(Error::kInvalidArguments,
369 kManagerErrorPassphraseRequired);
370 return NULL;
371 }
372
373 if (security_method == flimflam::kSecurityWep) {
374 string passphrase = args.GetString(flimflam::kPassphraseProperty);
375 passphrase = ParseWEPPassphrase(passphrase, error);
376 if (error->IsFailure()) {
377 return NULL;
378 }
mukesh agrawal8ede0522011-10-03 14:57:44 -0700379 } else if (security_method == flimflam::kSecurityPsk ||
380 security_method == flimflam::kSecurityWpa ||
381 security_method == flimflam::kSecurityRsn) {
382 string passphrase = args.GetString(flimflam::kPassphraseProperty);
383 passphrase = ParseWPAPassphrase(passphrase, error);
384 if (error->IsFailure()) {
385 return NULL;
386 }
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700387 }
388
389 WiFiService *service = NULL;
390
391 // TODO(quiche): search for existing service
392
393 if (service == NULL) {
394 // TODO(quiche): construct a new service
395 }
396
397 // TODO(quiche): apply configuration parameters
398
399 return service;
400}
401
402// static
403string WiFi::ParseWEPPassphrase(const string &passphrase, Error *error) {
404 unsigned int length = passphrase.length();
405
406 switch (length) {
407 case IEEE_80211::kWEP40AsciiLen:
408 case IEEE_80211::kWEP104AsciiLen:
409 break;
410 case IEEE_80211::kWEP40AsciiLen + 2:
411 case IEEE_80211::kWEP104AsciiLen + 2:
412 CheckWEPKeyIndex(passphrase, error);
413 break;
414 case IEEE_80211::kWEP40HexLen:
415 case IEEE_80211::kWEP104HexLen:
416 CheckWEPIsHex(passphrase, error);
417 break;
418 case IEEE_80211::kWEP40HexLen + 2:
419 case IEEE_80211::kWEP104HexLen + 2:
420 (CheckWEPKeyIndex(passphrase, error) ||
421 CheckWEPPrefix(passphrase, error)) &&
422 CheckWEPIsHex(passphrase.substr(2), error);
423 break;
424 case IEEE_80211::kWEP40HexLen + 4:
425 case IEEE_80211::kWEP104HexLen + 4:
426 CheckWEPKeyIndex(passphrase, error) &&
427 CheckWEPPrefix(passphrase.substr(2), error) &&
428 CheckWEPIsHex(passphrase.substr(4), error);
429 break;
430 default:
431 error->Populate(Error::kInvalidPassphrase);
432 break;
433 }
434
435 // TODO(quiche): may need to normalize passphrase format
436 if (error->IsSuccess()) {
437 return passphrase;
438 } else {
439 return "";
440 }
441}
442
443// static
mukesh agrawal8ede0522011-10-03 14:57:44 -0700444string WiFi::ParseWPAPassphrase(const string &passphrase, Error *error) {
445 unsigned int length = passphrase.length();
446 vector<uint8> passphrase_bytes;
447
448 if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
449 if (length != IEEE_80211::kWPAHexLen &&
450 (length < IEEE_80211::kWPAAsciiMinLen ||
451 length > IEEE_80211::kWPAAsciiMaxLen)) {
452 error->Populate(Error::kInvalidPassphrase);
453 }
454 } else {
455 if (length < IEEE_80211::kWPAAsciiMinLen ||
456 length > IEEE_80211::kWPAAsciiMaxLen) {
457 error->Populate(Error::kInvalidPassphrase);
458 }
459 }
460
461 // TODO(quiche): may need to normalize passphrase format
462 if (error->IsSuccess()) {
463 return passphrase;
464 } else {
465 return "";
466 }
467}
468
469// static
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700470bool WiFi::CheckWEPIsHex(const string &passphrase, Error *error) {
471 vector<uint8> passphrase_bytes;
472 if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
473 return true;
474 } else {
475 error->Populate(Error::kInvalidPassphrase);
476 return false;
477 }
478}
479
480// static
481bool WiFi::CheckWEPKeyIndex(const string &passphrase, Error *error) {
482 if (StartsWithASCII(passphrase, "0:", false) ||
483 StartsWithASCII(passphrase, "1:", false) ||
484 StartsWithASCII(passphrase, "2:", false) ||
485 StartsWithASCII(passphrase, "3:", false)) {
486 return true;
487 } else {
488 error->Populate(Error::kInvalidPassphrase);
489 return false;
490 }
491}
492
493// static
494bool WiFi::CheckWEPPrefix(const string &passphrase, Error *error) {
495 if (StartsWithASCII(passphrase, "0x", false)) {
496 return true;
497 } else {
498 error->Populate(Error::kInvalidPassphrase);
499 return false;
500 }
501}
502
Paul Stewartb50f0b92011-05-16 16:31:42 -0700503} // namespace shill