blob: 528c5da0e210dca34f3d6020c880bcd05c185a35 [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>
Paul Stewartb50f0b92011-05-16 16:31:42 -070010
mukesh agrawalab87ea42011-05-18 11:44:49 -070011#include <map>
Paul Stewartb50f0b92011-05-16 16:31:42 -070012#include <string>
mukesh agrawalab87ea42011-05-18 11:44:49 -070013#include <vector>
Paul Stewartb50f0b92011-05-16 16:31:42 -070014
15#include <base/logging.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070016#include <chromeos/dbus/service_constants.h>
Paul Stewartb50f0b92011-05-16 16:31:42 -070017
18#include "shill/control_interface.h"
19#include "shill/device.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070020#include "shill/manager.h"
21#include "shill/profile.h"
Darin Petkovd1967262011-07-18 14:55:18 -070022#include "shill/proxy_factory.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070023#include "shill/shill_event.h"
mukesh agrawalaf571952011-07-14 14:31:12 -070024#include "shill/supplicant_interface_proxy_interface.h"
25#include "shill/supplicant_process_proxy_interface.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070026#include "shill/wifi_endpoint.h"
27#include "shill/wifi_service.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070028
mukesh agrawalab87ea42011-05-18 11:44:49 -070029using std::string;
30
Paul Stewartb50f0b92011-05-16 16:31:42 -070031namespace shill {
mukesh agrawalb54601c2011-06-07 17:39:22 -070032const char WiFi::kSupplicantPath[] = "/fi/w1/wpa_supplicant1";
33const char WiFi::kSupplicantDBusAddr[] = "fi.w1.wpa_supplicant1";
34const char WiFi::kSupplicantWiFiDriver[] = "nl80211";
mukesh agrawalc7426a42011-06-03 13:04:28 -070035const char WiFi::kSupplicantErrorInterfaceExists[] =
36 "fi.w1.wpa_supplicant1.InterfaceExists";
mukesh agrawal445e72c2011-06-22 11:13:50 -070037const char WiFi::kSupplicantPropertySSID[] = "ssid";
38const char WiFi::kSupplicantPropertyNetworkMode[] = "mode";
39const char WiFi::kSupplicantPropertyKeyMode[] = "key_mgmt";
mukesh agrawalb54601c2011-06-07 17:39:22 -070040const char WiFi::kSupplicantKeyModeNone[] = "NONE";
41
mukesh agrawalab87ea42011-05-18 11:44:49 -070042// NB: we assume supplicant is already running. [quiche.20110518]
Paul Stewartb50f0b92011-05-16 16:31:42 -070043WiFi::WiFi(ControlInterface *control_interface,
44 EventDispatcher *dispatcher,
Paul Stewartf1ce5d22011-05-19 13:10:20 -070045 Manager *manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070046 const string& link,
Chris Masone626719f2011-08-18 16:58:48 -070047 const std::string &address,
Paul Stewartb50f0b92011-05-16 16:31:42 -070048 int interface_index)
Chris Masonea82b7112011-05-25 15:16:29 -070049 : Device(control_interface,
50 dispatcher,
51 manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070052 link,
Chris Masone626719f2011-08-18 16:58:48 -070053 address,
mukesh agrawalab87ea42011-05-18 11:44:49 -070054 interface_index),
mukesh agrawalb54601c2011-06-07 17:39:22 -070055 task_factory_(this),
Chris Masone853b81b2011-06-24 14:11:41 -070056 bgscan_short_interval_(0),
57 bgscan_signal_threshold_(0),
58 scan_pending_(false),
59 scan_interval_(0) {
Paul Stewartac4ac002011-08-26 12:04:26 -070060 PropertyStore *store = this->store();
61 store->RegisterString(flimflam::kBgscanMethodProperty, &bgscan_method_);
62 store->RegisterUint16(flimflam::kBgscanShortIntervalProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070063 &bgscan_short_interval_);
Paul Stewartac4ac002011-08-26 12:04:26 -070064 store->RegisterInt32(flimflam::kBgscanSignalThresholdProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070065 &bgscan_signal_threshold_);
66
Chris Masoneb925cc82011-06-22 15:39:57 -070067 // TODO(quiche): Decide if scan_pending_ is close enough to
68 // "currently scanning" that we don't care, or if we want to track
69 // scan pending/currently scanning/no scan scheduled as a tri-state
70 // kind of thing.
Paul Stewartac4ac002011-08-26 12:04:26 -070071 store->RegisterConstBool(flimflam::kScanningProperty, &scan_pending_);
72 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
73 VLOG(2) << "WiFi device " << link_name() << " initialized.";
Paul Stewartb50f0b92011-05-16 16:31:42 -070074}
75
mukesh agrawalaf571952011-07-14 14:31:12 -070076WiFi::~WiFi() {}
Paul Stewartb50f0b92011-05-16 16:31:42 -070077
mukesh agrawalab87ea42011-05-18 11:44:49 -070078void WiFi::Start() {
mukesh agrawalab87ea42011-05-18 11:44:49 -070079 ::DBus::Path interface_path;
80
mukesh agrawalaf571952011-07-14 14:31:12 -070081 supplicant_process_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -070082 ProxyFactory::factory()->CreateSupplicantProcessProxy(
mukesh agrawalaf571952011-07-14 14:31:12 -070083 kSupplicantPath, kSupplicantDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -070084 try {
85 std::map<string, DBus::Variant> create_interface_args;
86 create_interface_args["Ifname"].writer().
Paul Stewartac4ac002011-08-26 12:04:26 -070087 append_string(link_name().c_str());
mukesh agrawalc7426a42011-06-03 13:04:28 -070088 create_interface_args["Driver"].writer().
89 append_string(kSupplicantWiFiDriver);
90 // TODO(quiche) create_interface_args["ConfigFile"].writer().append_string
91 // (file with pkcs config info)
92 interface_path =
93 supplicant_process_proxy_->CreateInterface(create_interface_args);
94 } catch (const DBus::Error e) { // NOLINT
95 if (!strcmp(e.name(), kSupplicantErrorInterfaceExists)) {
96 interface_path =
Paul Stewartac4ac002011-08-26 12:04:26 -070097 supplicant_process_proxy_->GetInterface(link_name());
mukesh agrawalb54601c2011-06-07 17:39:22 -070098 // XXX crash here, if device missing?
mukesh agrawalc7426a42011-06-03 13:04:28 -070099 } else {
100 // XXX
101 }
102 }
103
mukesh agrawalab87ea42011-05-18 11:44:49 -0700104 supplicant_interface_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -0700105 ProxyFactory::factory()->CreateSupplicantInterfaceProxy(
mukesh agrawalaf571952011-07-14 14:31:12 -0700106 this, interface_path, kSupplicantDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -0700107
mukesh agrawalab87ea42011-05-18 11:44:49 -0700108 // TODO(quiche) set ApScan=1 and BSSExpireAge=190, like flimflam does?
mukesh agrawalc7426a42011-06-03 13:04:28 -0700109
110 // clear out any networks that might previously have been configured
111 // for this interface.
112 supplicant_interface_proxy_->RemoveAllNetworks();
113
114 // flush interface's BSS cache, so that we get BSSAdded signals for
115 // all BSSes (not just new ones since the last scan).
116 supplicant_interface_proxy_->FlushBSS(0);
117
mukesh agrawalab87ea42011-05-18 11:44:49 -0700118 LOG(INFO) << "initiating Scan.";
mukesh agrawalc7426a42011-06-03 13:04:28 -0700119 std::map<string, DBus::Variant> scan_args;
120 scan_args["Type"].writer().append_string("active");
mukesh agrawalab87ea42011-05-18 11:44:49 -0700121 // TODO(quiche) indicate scanning in UI
122 supplicant_interface_proxy_->Scan(scan_args);
123 scan_pending_ = true;
124 Device::Start();
125}
126
mukesh agrawalab87ea42011-05-18 11:44:49 -0700127void WiFi::Stop() {
128 LOG(INFO) << __func__;
mukesh agrawal31950242011-07-14 11:53:38 -0700129 // TODO(quiche): remove interface from supplicant
130 supplicant_interface_proxy_.reset(); // breaks a reference cycle
131 supplicant_process_proxy_.reset();
132 endpoint_by_bssid_.clear();
133 service_by_private_id_.clear(); // breaks reference cycles
mukesh agrawalab87ea42011-05-18 11:44:49 -0700134 Device::Stop();
mukesh agrawal31950242011-07-14 11:53:38 -0700135 // XXX anything else to do?
mukesh agrawalab87ea42011-05-18 11:44:49 -0700136}
137
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700138bool WiFi::TechnologyIs(const Device::Technology type) const {
Paul Stewartb50f0b92011-05-16 16:31:42 -0700139 return type == Device::kWifi;
140}
141
mukesh agrawalb54601c2011-06-07 17:39:22 -0700142void WiFi::BSSAdded(
143 const ::DBus::Path &BSS,
144 const std::map<string, ::DBus::Variant> &properties) {
145 // TODO(quiche): write test to verify correct behavior in the case
146 // where we get multiple BSSAdded events for a single endpoint.
147 // (old Endpoint's refcount should fall to zero, and old Endpoint
148 // should be destroyed)
149 //
150 // note: we assume that BSSIDs are unique across endpoints. this
151 // means that if an AP reuses the same BSSID for multiple SSIDs, we
152 // lose.
153 WiFiEndpointRefPtr endpoint(new WiFiEndpoint(properties));
154 endpoint_by_bssid_[endpoint->bssid_hex()] = endpoint;
155}
156
157void WiFi::ScanDone() {
158 LOG(INFO) << __func__;
159
160 // defer handling of scan result processing, because that processing
161 // may require the the registration of new D-Bus objects. and such
162 // registration can't be done in the context of a D-Bus signal
163 // handler.
Paul Stewartac4ac002011-08-26 12:04:26 -0700164 dispatcher()->PostTask(
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700165 task_factory_.NewRunnableMethod(&WiFi::ScanDoneTask));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700166}
167
mukesh agrawal445e72c2011-06-22 11:13:50 -0700168void WiFi::ConnectTo(const WiFiService &service) {
169 std::map<string, DBus::Variant> add_network_args;
170 DBus::MessageIter writer;
171 DBus::Path network_path;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700172
mukesh agrawal445e72c2011-06-22 11:13:50 -0700173 add_network_args[kSupplicantPropertyNetworkMode].writer().
Chris Masone092df3e2011-08-22 09:41:39 -0700174 append_uint32(WiFiEndpoint::ModeStringToUint(service.mode()));
mukesh agrawal445e72c2011-06-22 11:13:50 -0700175 add_network_args[kSupplicantPropertyKeyMode].writer().
176 append_string(service.key_management().c_str());
177 // TODO(quiche): figure out why we can't use operator<< without the
178 // temporary variable.
179 writer = add_network_args[kSupplicantPropertySSID].writer();
180 writer << service.ssid();
181 // TODO(quiche): set scan_ssid=1, like flimflam does?
182
183 network_path =
184 supplicant_interface_proxy_->AddNetwork(add_network_args);
185 supplicant_interface_proxy_->SelectNetwork(network_path);
186 // XXX add to favorite networks list?
mukesh agrawalb54601c2011-06-07 17:39:22 -0700187}
188
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700189void WiFi::ScanDoneTask() {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700190 LOG(INFO) << __func__;
191
192 scan_pending_ = false;
193
194 // TODO(quiche): group endpoints into services, instead of creating
195 // a service for every endpoint.
196 for (EndpointMap::iterator i(endpoint_by_bssid_.begin());
197 i != endpoint_by_bssid_.end(); ++i) {
198 const WiFiEndpoint &endpoint(*(i->second));
199 string service_id_private;
200
201 service_id_private =
202 endpoint.ssid_hex() + "_" + endpoint.bssid_hex();
203 if (service_by_private_id_.find(service_id_private) ==
204 service_by_private_id_.end()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700205 LOG(INFO) << "found new endpoint. "
206 << "ssid: " << endpoint.ssid_string() << ", "
207 << "bssid: " << endpoint.bssid_string() << ", "
mukesh agrawal51a7e932011-07-27 16:18:26 -0700208 << "signal: " << endpoint.signal_strength();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700209
210 // XXX key mode should reflect endpoint params (not always use
211 // kSupplicantKeyModeNone)
mukesh agrawal31950242011-07-14 11:53:38 -0700212 WiFiServiceRefPtr service(
Paul Stewartac4ac002011-08-26 12:04:26 -0700213 new WiFiService(control_interface(),
214 dispatcher(),
215 manager(),
Chris Masone7aa5f902011-07-11 11:13:35 -0700216 this,
Chris Masone7aa5f902011-07-11 11:13:35 -0700217 endpoint.ssid(),
218 endpoint.network_mode(),
mukesh agrawal51a7e932011-07-27 16:18:26 -0700219 kSupplicantKeyModeNone));
Paul Stewartac4ac002011-08-26 12:04:26 -0700220 services()->push_back(service);
mukesh agrawalb54601c2011-06-07 17:39:22 -0700221 service_by_private_id_[service_id_private] = service;
mukesh agrawal51a7e932011-07-27 16:18:26 -0700222
223 LOG(INFO) << "new service " << service->GetRpcIdentifier();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700224 }
225 }
226
227 // TODO(quiche): register new services with manager
228 // TODO(quiche): unregister removed services from manager
229}
230
Paul Stewartb50f0b92011-05-16 16:31:42 -0700231} // namespace shill