blob: 18195ec04e0601758d80e883ed4b3b7166246258 [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"
Paul Stewartb50f0b92011-05-16 16:31:42 -070035
mukesh agrawal7a4e4002011-09-06 11:26:05 -070036using std::map;
mukesh agrawalab87ea42011-05-18 11:44:49 -070037using std::string;
mukesh agrawal7a4e4002011-09-06 11:26:05 -070038using std::vector;
mukesh agrawalab87ea42011-05-18 11:44:49 -070039
Paul Stewartb50f0b92011-05-16 16:31:42 -070040namespace shill {
mukesh agrawal7a4e4002011-09-06 11:26:05 -070041
42// statics
43//
44// Note that WiFi generates some manager-level errors, because it implements
45// the Manager.GetWiFiService flimflam API. The API is implemented here,
46// rather than in manager, to keep WiFi-specific logic in the right place.
47const char WiFi::kManagerErrorPassphraseRequired[] = "must specify passphrase";
48const char WiFi::kManagerErrorSSIDRequired[] = "must specify SSID";
49const char WiFi::kManagerErrorSSIDTooLong[] = "SSID is too long";
50const char WiFi::kManagerErrorSSIDTooShort[] = "SSID is too short";
51const char WiFi::kManagerErrorTypeRequired[] = "must specify service type";
52const char WiFi::kManagerErrorUnsupportedSecurityMode[] =
53 "security mode is unsupported";
54const char WiFi::kManagerErrorUnsupportedServiceType[] =
55 "service type is unsupported";
56const char WiFi::kManagerErrorUnsupportedServiceMode[] =
57 "service mode is unsupported";
mukesh agrawalb54601c2011-06-07 17:39:22 -070058const char WiFi::kSupplicantPath[] = "/fi/w1/wpa_supplicant1";
59const char WiFi::kSupplicantDBusAddr[] = "fi.w1.wpa_supplicant1";
60const char WiFi::kSupplicantWiFiDriver[] = "nl80211";
mukesh agrawalc7426a42011-06-03 13:04:28 -070061const char WiFi::kSupplicantErrorInterfaceExists[] =
62 "fi.w1.wpa_supplicant1.InterfaceExists";
mukesh agrawal445e72c2011-06-22 11:13:50 -070063const char WiFi::kSupplicantPropertySSID[] = "ssid";
64const char WiFi::kSupplicantPropertyNetworkMode[] = "mode";
65const char WiFi::kSupplicantPropertyKeyMode[] = "key_mgmt";
mukesh agrawal32399322011-09-01 10:53:43 -070066const char WiFi::kSupplicantPropertyScanType[] = "Type";
mukesh agrawalb54601c2011-06-07 17:39:22 -070067const char WiFi::kSupplicantKeyModeNone[] = "NONE";
mukesh agrawal32399322011-09-01 10:53:43 -070068const char WiFi::kSupplicantScanTypeActive[] = "active";
mukesh agrawalb54601c2011-06-07 17:39:22 -070069
mukesh agrawalab87ea42011-05-18 11:44:49 -070070// NB: we assume supplicant is already running. [quiche.20110518]
Paul Stewartb50f0b92011-05-16 16:31:42 -070071WiFi::WiFi(ControlInterface *control_interface,
72 EventDispatcher *dispatcher,
Paul Stewartf1ce5d22011-05-19 13:10:20 -070073 Manager *manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070074 const string& link,
Chris Masone626719f2011-08-18 16:58:48 -070075 const std::string &address,
Paul Stewartb50f0b92011-05-16 16:31:42 -070076 int interface_index)
Chris Masonea82b7112011-05-25 15:16:29 -070077 : Device(control_interface,
78 dispatcher,
79 manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070080 link,
Chris Masone626719f2011-08-18 16:58:48 -070081 address,
mukesh agrawalab87ea42011-05-18 11:44:49 -070082 interface_index),
mukesh agrawalb54601c2011-06-07 17:39:22 -070083 task_factory_(this),
Chris Masone853b81b2011-06-24 14:11:41 -070084 bgscan_short_interval_(0),
85 bgscan_signal_threshold_(0),
86 scan_pending_(false),
mukesh agrawalf2f68a52011-09-01 12:15:48 -070087 scan_interval_(0),
88 link_up_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -070089 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -070090 store->RegisterString(flimflam::kBgscanMethodProperty, &bgscan_method_);
91 store->RegisterUint16(flimflam::kBgscanShortIntervalProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070092 &bgscan_short_interval_);
Paul Stewartac4ac002011-08-26 12:04:26 -070093 store->RegisterInt32(flimflam::kBgscanSignalThresholdProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070094 &bgscan_signal_threshold_);
95
Chris Masoneb925cc82011-06-22 15:39:57 -070096 // TODO(quiche): Decide if scan_pending_ is close enough to
97 // "currently scanning" that we don't care, or if we want to track
98 // scan pending/currently scanning/no scan scheduled as a tri-state
99 // kind of thing.
Paul Stewartac4ac002011-08-26 12:04:26 -0700100 store->RegisterConstBool(flimflam::kScanningProperty, &scan_pending_);
101 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
102 VLOG(2) << "WiFi device " << link_name() << " initialized.";
Paul Stewartb50f0b92011-05-16 16:31:42 -0700103}
104
mukesh agrawalaf571952011-07-14 14:31:12 -0700105WiFi::~WiFi() {}
Paul Stewartb50f0b92011-05-16 16:31:42 -0700106
mukesh agrawalab87ea42011-05-18 11:44:49 -0700107void WiFi::Start() {
mukesh agrawalab87ea42011-05-18 11:44:49 -0700108 ::DBus::Path interface_path;
109
mukesh agrawalaf571952011-07-14 14:31:12 -0700110 supplicant_process_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -0700111 ProxyFactory::factory()->CreateSupplicantProcessProxy(
mukesh agrawalaf571952011-07-14 14:31:12 -0700112 kSupplicantPath, kSupplicantDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -0700113 try {
114 std::map<string, DBus::Variant> create_interface_args;
115 create_interface_args["Ifname"].writer().
Paul Stewartac4ac002011-08-26 12:04:26 -0700116 append_string(link_name().c_str());
mukesh agrawalc7426a42011-06-03 13:04:28 -0700117 create_interface_args["Driver"].writer().
118 append_string(kSupplicantWiFiDriver);
119 // TODO(quiche) create_interface_args["ConfigFile"].writer().append_string
120 // (file with pkcs config info)
121 interface_path =
122 supplicant_process_proxy_->CreateInterface(create_interface_args);
123 } catch (const DBus::Error e) { // NOLINT
124 if (!strcmp(e.name(), kSupplicantErrorInterfaceExists)) {
125 interface_path =
Paul Stewartac4ac002011-08-26 12:04:26 -0700126 supplicant_process_proxy_->GetInterface(link_name());
mukesh agrawalb54601c2011-06-07 17:39:22 -0700127 // XXX crash here, if device missing?
mukesh agrawalc7426a42011-06-03 13:04:28 -0700128 } else {
129 // XXX
130 }
131 }
132
mukesh agrawalab87ea42011-05-18 11:44:49 -0700133 supplicant_interface_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -0700134 ProxyFactory::factory()->CreateSupplicantInterfaceProxy(
mukesh agrawalaf571952011-07-14 14:31:12 -0700135 this, interface_path, kSupplicantDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -0700136
mukesh agrawalab87ea42011-05-18 11:44:49 -0700137 // TODO(quiche) set ApScan=1 and BSSExpireAge=190, like flimflam does?
mukesh agrawalc7426a42011-06-03 13:04:28 -0700138
139 // clear out any networks that might previously have been configured
140 // for this interface.
141 supplicant_interface_proxy_->RemoveAllNetworks();
142
143 // flush interface's BSS cache, so that we get BSSAdded signals for
144 // all BSSes (not just new ones since the last scan).
145 supplicant_interface_proxy_->FlushBSS(0);
146
Darin Petkovc0865312011-09-16 15:31:20 -0700147 Scan(NULL);
mukesh agrawalab87ea42011-05-18 11:44:49 -0700148 Device::Start();
149}
150
mukesh agrawalab87ea42011-05-18 11:44:49 -0700151void WiFi::Stop() {
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700152 VLOG(2) << "WiFi " << link_name() << " stopping.";
mukesh agrawal31950242011-07-14 11:53:38 -0700153 // TODO(quiche): remove interface from supplicant
154 supplicant_interface_proxy_.reset(); // breaks a reference cycle
155 supplicant_process_proxy_.reset();
156 endpoint_by_bssid_.clear();
157 service_by_private_id_.clear(); // breaks reference cycles
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700158
159 for (std::vector<ServiceRefPtr>::const_iterator it = services()->begin();
160 it != services()->end();
161 ++it) {
162 manager()->DeregisterService(*it);
163 }
164 services()->clear(); // breaks reference cycles
165
mukesh agrawalab87ea42011-05-18 11:44:49 -0700166 Device::Stop();
mukesh agrawal31950242011-07-14 11:53:38 -0700167 // XXX anything else to do?
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700168
169 VLOG(3) << "WiFi " << link_name() << " task_factory_ "
170 << (task_factory_.empty() ? "is empty." : "is not empty.");
171 VLOG(3) << "WiFi " << link_name() << " supplicant_process_proxy_ "
172 << (supplicant_process_proxy_.get() ? "is set." : "is not set.");
173 VLOG(3) << "WiFi " << link_name() << " supplicant_interface_proxy_ "
174 << (supplicant_interface_proxy_.get() ? "is set." : "is not set.");
175 VLOG(3) << "WiFi " << link_name() << " has " << endpoint_by_bssid_.size()
176 << " EndpointMap entries.";
177 VLOG(3) << "WiFi " << link_name() << " has " << service_by_private_id_.size()
178 << " ServiceMap entries.";
mukesh agrawalab87ea42011-05-18 11:44:49 -0700179}
180
Darin Petkovc0865312011-09-16 15:31:20 -0700181void WiFi::Scan(Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -0700182 LOG(INFO) << __func__;
183
184 // needs to send a D-Bus message, but may be called from D-Bus
185 // signal handler context (via Manager::RequestScan). so defer work
186 // to event loop.
187 dispatcher()->PostTask(
188 task_factory_.NewRunnableMethod(&WiFi::ScanTask));
189}
190
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700191bool WiFi::TechnologyIs(const Device::Technology type) const {
Paul Stewartb50f0b92011-05-16 16:31:42 -0700192 return type == Device::kWifi;
193}
194
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700195void WiFi::LinkEvent(unsigned int flags, unsigned int change) {
196 // TODO(quiche): figure out how to relate these events to supplicant
197 // events. e.g., may be we can ignore LinkEvent, in favor of events
198 // from SupplicantInterfaceProxy?
199 Device::LinkEvent(flags, change);
200 if ((flags & IFF_LOWER_UP) != 0 && !link_up_) {
201 LOG(INFO) << link_name() << " is up; should start L3!";
202 link_up_ = true;
203 if (AcquireDHCPConfig()) {
204 SetServiceState(Service::kStateConfiguring);
205 } else {
206 LOG(ERROR) << "Unable to acquire DHCP config.";
207 }
208 } else if ((flags & IFF_LOWER_UP) == 0 && link_up_) {
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700209 LOG(INFO) << link_name() << " is down";
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700210 link_up_ = false;
211 // TODO(quiche): attempt to reconnect to current SSID, another SSID,
212 // or initiate a scan.
213 }
214}
215
mukesh agrawalb54601c2011-06-07 17:39:22 -0700216void WiFi::BSSAdded(
217 const ::DBus::Path &BSS,
218 const std::map<string, ::DBus::Variant> &properties) {
219 // TODO(quiche): write test to verify correct behavior in the case
220 // where we get multiple BSSAdded events for a single endpoint.
221 // (old Endpoint's refcount should fall to zero, and old Endpoint
222 // should be destroyed)
223 //
224 // note: we assume that BSSIDs are unique across endpoints. this
225 // means that if an AP reuses the same BSSID for multiple SSIDs, we
226 // lose.
227 WiFiEndpointRefPtr endpoint(new WiFiEndpoint(properties));
228 endpoint_by_bssid_[endpoint->bssid_hex()] = endpoint;
229}
230
231void WiFi::ScanDone() {
232 LOG(INFO) << __func__;
233
234 // defer handling of scan result processing, because that processing
235 // may require the the registration of new D-Bus objects. and such
236 // registration can't be done in the context of a D-Bus signal
237 // handler.
Paul Stewartac4ac002011-08-26 12:04:26 -0700238 dispatcher()->PostTask(
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700239 task_factory_.NewRunnableMethod(&WiFi::ScanDoneTask));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700240}
241
mukesh agrawal32399322011-09-01 10:53:43 -0700242void WiFi::ConnectTo(WiFiService *service) {
mukesh agrawal445e72c2011-06-22 11:13:50 -0700243 std::map<string, DBus::Variant> add_network_args;
244 DBus::MessageIter writer;
245 DBus::Path network_path;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700246
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700247 // TODO(quiche): handle cases where already connected
mukesh agrawal32399322011-09-01 10:53:43 -0700248
mukesh agrawal445e72c2011-06-22 11:13:50 -0700249 add_network_args[kSupplicantPropertyNetworkMode].writer().
mukesh agrawal32399322011-09-01 10:53:43 -0700250 append_uint32(WiFiEndpoint::ModeStringToUint(service->mode()));
mukesh agrawal445e72c2011-06-22 11:13:50 -0700251 add_network_args[kSupplicantPropertyKeyMode].writer().
mukesh agrawal32399322011-09-01 10:53:43 -0700252 append_string(service->key_management().c_str());
mukesh agrawal445e72c2011-06-22 11:13:50 -0700253 // TODO(quiche): figure out why we can't use operator<< without the
254 // temporary variable.
255 writer = add_network_args[kSupplicantPropertySSID].writer();
mukesh agrawal32399322011-09-01 10:53:43 -0700256 writer << service->ssid();
mukesh agrawal445e72c2011-06-22 11:13:50 -0700257 // TODO(quiche): set scan_ssid=1, like flimflam does?
258
259 network_path =
260 supplicant_interface_proxy_->AddNetwork(add_network_args);
261 supplicant_interface_proxy_->SelectNetwork(network_path);
262 // XXX add to favorite networks list?
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700263
264 // SelectService here (instead of in LinkEvent, like Ethernet), so
265 // that, if we fail to bring up L2, we can attribute failure correctly.
266 //
267 // TODO(quiche): when we add code for dealing with connection failures,
268 // reconsider if this is the right place to change the selected service.
269 // see discussion in crosbug.com/20191.
270 SelectService(service);
mukesh agrawalb54601c2011-06-07 17:39:22 -0700271}
272
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700273void WiFi::ScanDoneTask() {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700274 LOG(INFO) << __func__;
275
276 scan_pending_ = false;
277
278 // TODO(quiche): group endpoints into services, instead of creating
279 // a service for every endpoint.
280 for (EndpointMap::iterator i(endpoint_by_bssid_.begin());
281 i != endpoint_by_bssid_.end(); ++i) {
282 const WiFiEndpoint &endpoint(*(i->second));
283 string service_id_private;
284
285 service_id_private =
286 endpoint.ssid_hex() + "_" + endpoint.bssid_hex();
287 if (service_by_private_id_.find(service_id_private) ==
288 service_by_private_id_.end()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700289 LOG(INFO) << "found new endpoint. "
290 << "ssid: " << endpoint.ssid_string() << ", "
291 << "bssid: " << endpoint.bssid_string() << ", "
mukesh agrawal51a7e932011-07-27 16:18:26 -0700292 << "signal: " << endpoint.signal_strength();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700293
294 // XXX key mode should reflect endpoint params (not always use
295 // kSupplicantKeyModeNone)
mukesh agrawal31950242011-07-14 11:53:38 -0700296 WiFiServiceRefPtr service(
Paul Stewartac4ac002011-08-26 12:04:26 -0700297 new WiFiService(control_interface(),
298 dispatcher(),
299 manager(),
Chris Masone7aa5f902011-07-11 11:13:35 -0700300 this,
Chris Masone7aa5f902011-07-11 11:13:35 -0700301 endpoint.ssid(),
302 endpoint.network_mode(),
mukesh agrawal51a7e932011-07-27 16:18:26 -0700303 kSupplicantKeyModeNone));
Paul Stewartac4ac002011-08-26 12:04:26 -0700304 services()->push_back(service);
mukesh agrawalb54601c2011-06-07 17:39:22 -0700305 service_by_private_id_[service_id_private] = service;
mukesh agrawal32399322011-09-01 10:53:43 -0700306 manager()->RegisterService(service);
mukesh agrawal51a7e932011-07-27 16:18:26 -0700307
308 LOG(INFO) << "new service " << service->GetRpcIdentifier();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700309 }
310 }
311
mukesh agrawalb54601c2011-06-07 17:39:22 -0700312 // TODO(quiche): unregister removed services from manager
313}
314
mukesh agrawal32399322011-09-01 10:53:43 -0700315void WiFi::ScanTask() {
316 VLOG(2) << "WiFi " << link_name() << " scan requested.";
317 std::map<string, DBus::Variant> scan_args;
318 scan_args[kSupplicantPropertyScanType].writer().
319 append_string(kSupplicantScanTypeActive);
320 // TODO(quiche) indicate scanning in UI
321 supplicant_interface_proxy_->Scan(scan_args);
322 scan_pending_ = true;
323}
324
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700325// used by manager, via static WiFi::GetService method
326WiFiServiceRefPtr WiFi::GetService(const KeyValueStore &args, Error *error) {
327 if (!args.ContainsString(flimflam::kTypeProperty)) {
328 error->Populate(Error::kInvalidArguments, kManagerErrorTypeRequired);
329 return NULL;
330 }
331
332 if (args.GetString(flimflam::kTypeProperty) != flimflam::kTypeWifi) {
333 error->Populate(Error::kNotSupported, kManagerErrorUnsupportedServiceType);
334 return NULL;
335 }
336
337 if (args.ContainsString(flimflam::kModeProperty) &&
338 args.GetString(flimflam::kModeProperty) !=
339 flimflam::kModeManaged) {
340 error->Populate(Error::kNotSupported, kManagerErrorUnsupportedServiceMode);
341 return NULL;
342 }
343
344 if (!args.ContainsString(flimflam::kSSIDProperty)) {
345 error->Populate(Error::kInvalidArguments, kManagerErrorSSIDRequired);
346 return NULL;
347 }
348
349 string ssid = args.GetString(flimflam::kSSIDProperty);
350 if (ssid.length() < 1) {
351 error->Populate(Error::kInvalidNetworkName, kManagerErrorSSIDTooShort);
352 return NULL;
353 }
354
355 if (ssid.length() > IEEE_80211::kMaxSSIDLen) {
356 error->Populate(Error::kInvalidNetworkName, kManagerErrorSSIDTooLong);
357 return NULL;
358 }
359
360 string security_method;
361 if (args.ContainsString(flimflam::kSecurityProperty)) {
362 security_method = args.GetString(flimflam::kSecurityProperty);
363 } else {
364 security_method = flimflam::kSecurityNone;
365 }
366
367 if (security_method != flimflam::kSecurityNone &&
368 security_method != flimflam::kSecurityWep &&
369 security_method != flimflam::kSecurityPsk &&
370 security_method != flimflam::kSecurityWpa &&
371 security_method != flimflam::kSecurityRsn &&
372 security_method != flimflam::kSecurity8021x) {
373 error->Populate(Error::kNotSupported,
374 kManagerErrorUnsupportedSecurityMode);
375 return NULL;
376 }
377
378 if ((security_method == flimflam::kSecurityWep ||
379 security_method == flimflam::kSecurityPsk ||
380 security_method == flimflam::kSecurityWpa ||
381 security_method == flimflam::kSecurityRsn) &&
382 !args.ContainsString(flimflam::kPassphraseProperty)) {
383 error->Populate(Error::kInvalidArguments,
384 kManagerErrorPassphraseRequired);
385 return NULL;
386 }
387
388 if (security_method == flimflam::kSecurityWep) {
389 string passphrase = args.GetString(flimflam::kPassphraseProperty);
390 passphrase = ParseWEPPassphrase(passphrase, error);
391 if (error->IsFailure()) {
392 return NULL;
393 }
394 }
395
396 WiFiService *service = NULL;
397
398 // TODO(quiche): search for existing service
399
400 if (service == NULL) {
401 // TODO(quiche): construct a new service
402 }
403
404 // TODO(quiche): apply configuration parameters
405
406 return service;
407}
408
409// static
410string WiFi::ParseWEPPassphrase(const string &passphrase, Error *error) {
411 unsigned int length = passphrase.length();
412
413 switch (length) {
414 case IEEE_80211::kWEP40AsciiLen:
415 case IEEE_80211::kWEP104AsciiLen:
416 break;
417 case IEEE_80211::kWEP40AsciiLen + 2:
418 case IEEE_80211::kWEP104AsciiLen + 2:
419 CheckWEPKeyIndex(passphrase, error);
420 break;
421 case IEEE_80211::kWEP40HexLen:
422 case IEEE_80211::kWEP104HexLen:
423 CheckWEPIsHex(passphrase, error);
424 break;
425 case IEEE_80211::kWEP40HexLen + 2:
426 case IEEE_80211::kWEP104HexLen + 2:
427 (CheckWEPKeyIndex(passphrase, error) ||
428 CheckWEPPrefix(passphrase, error)) &&
429 CheckWEPIsHex(passphrase.substr(2), error);
430 break;
431 case IEEE_80211::kWEP40HexLen + 4:
432 case IEEE_80211::kWEP104HexLen + 4:
433 CheckWEPKeyIndex(passphrase, error) &&
434 CheckWEPPrefix(passphrase.substr(2), error) &&
435 CheckWEPIsHex(passphrase.substr(4), error);
436 break;
437 default:
438 error->Populate(Error::kInvalidPassphrase);
439 break;
440 }
441
442 // TODO(quiche): may need to normalize passphrase format
443 if (error->IsSuccess()) {
444 return passphrase;
445 } else {
446 return "";
447 }
448}
449
450// static
451bool WiFi::CheckWEPIsHex(const string &passphrase, Error *error) {
452 vector<uint8> passphrase_bytes;
453 if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
454 return true;
455 } else {
456 error->Populate(Error::kInvalidPassphrase);
457 return false;
458 }
459}
460
461// static
462bool WiFi::CheckWEPKeyIndex(const string &passphrase, Error *error) {
463 if (StartsWithASCII(passphrase, "0:", false) ||
464 StartsWithASCII(passphrase, "1:", false) ||
465 StartsWithASCII(passphrase, "2:", false) ||
466 StartsWithASCII(passphrase, "3:", false)) {
467 return true;
468 } else {
469 error->Populate(Error::kInvalidPassphrase);
470 return false;
471 }
472}
473
474// static
475bool WiFi::CheckWEPPrefix(const string &passphrase, Error *error) {
476 if (StartsWithASCII(passphrase, "0x", false)) {
477 return true;
478 } else {
479 error->Populate(Error::kInvalidPassphrase);
480 return false;
481 }
482}
483
Paul Stewartb50f0b92011-05-16 16:31:42 -0700484} // namespace shill