blob: 6db73ab7bb1fa32b59c621190cafc2f63d7196dd [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,
Paul Stewartb50f0b92011-05-16 16:31:42 -070047 int interface_index)
Chris Masonea82b7112011-05-25 15:16:29 -070048 : Device(control_interface,
49 dispatcher,
50 manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070051 link,
mukesh agrawalab87ea42011-05-18 11:44:49 -070052 interface_index),
mukesh agrawalb54601c2011-06-07 17:39:22 -070053 task_factory_(this),
Chris Masone853b81b2011-06-24 14:11:41 -070054 bgscan_short_interval_(0),
55 bgscan_signal_threshold_(0),
56 scan_pending_(false),
57 scan_interval_(0) {
Chris Masone27c4aa52011-07-02 13:10:14 -070058 store_.RegisterString(flimflam::kBgscanMethodProperty, &bgscan_method_);
59 store_.RegisterUint16(flimflam::kBgscanShortIntervalProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070060 &bgscan_short_interval_);
Chris Masone27c4aa52011-07-02 13:10:14 -070061 store_.RegisterInt32(flimflam::kBgscanSignalThresholdProperty,
Chris Masone853b81b2011-06-24 14:11:41 -070062 &bgscan_signal_threshold_);
63
Chris Masoneb925cc82011-06-22 15:39:57 -070064 // TODO(quiche): Decide if scan_pending_ is close enough to
65 // "currently scanning" that we don't care, or if we want to track
66 // scan pending/currently scanning/no scan scheduled as a tri-state
67 // kind of thing.
Chris Masone27c4aa52011-07-02 13:10:14 -070068 store_.RegisterConstBool(flimflam::kScanningProperty, &scan_pending_);
69 store_.RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Chris Masone7df0c672011-07-15 10:24:54 -070070 VLOG(2) << "WiFi device " << link_name_ << " initialized.";
Paul Stewartb50f0b92011-05-16 16:31:42 -070071}
72
mukesh agrawalaf571952011-07-14 14:31:12 -070073WiFi::~WiFi() {}
Paul Stewartb50f0b92011-05-16 16:31:42 -070074
mukesh agrawalab87ea42011-05-18 11:44:49 -070075void WiFi::Start() {
mukesh agrawalab87ea42011-05-18 11:44:49 -070076 ::DBus::Path interface_path;
77
mukesh agrawalaf571952011-07-14 14:31:12 -070078 supplicant_process_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -070079 ProxyFactory::factory()->CreateSupplicantProcessProxy(
mukesh agrawalaf571952011-07-14 14:31:12 -070080 kSupplicantPath, kSupplicantDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -070081 try {
82 std::map<string, DBus::Variant> create_interface_args;
83 create_interface_args["Ifname"].writer().
Chris Masone7df0c672011-07-15 10:24:54 -070084 append_string(link_name_.c_str());
mukesh agrawalc7426a42011-06-03 13:04:28 -070085 create_interface_args["Driver"].writer().
86 append_string(kSupplicantWiFiDriver);
87 // TODO(quiche) create_interface_args["ConfigFile"].writer().append_string
88 // (file with pkcs config info)
89 interface_path =
90 supplicant_process_proxy_->CreateInterface(create_interface_args);
91 } catch (const DBus::Error e) { // NOLINT
92 if (!strcmp(e.name(), kSupplicantErrorInterfaceExists)) {
93 interface_path =
Chris Masone7df0c672011-07-15 10:24:54 -070094 supplicant_process_proxy_->GetInterface(link_name_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070095 // XXX crash here, if device missing?
mukesh agrawalc7426a42011-06-03 13:04:28 -070096 } else {
97 // XXX
98 }
99 }
100
mukesh agrawalab87ea42011-05-18 11:44:49 -0700101 supplicant_interface_proxy_.reset(
Darin Petkovaceede32011-07-18 15:32:38 -0700102 ProxyFactory::factory()->CreateSupplicantInterfaceProxy(
mukesh agrawalaf571952011-07-14 14:31:12 -0700103 this, interface_path, kSupplicantDBusAddr));
mukesh agrawalc7426a42011-06-03 13:04:28 -0700104
mukesh agrawalab87ea42011-05-18 11:44:49 -0700105 // TODO(quiche) set ApScan=1 and BSSExpireAge=190, like flimflam does?
mukesh agrawalc7426a42011-06-03 13:04:28 -0700106
107 // clear out any networks that might previously have been configured
108 // for this interface.
109 supplicant_interface_proxy_->RemoveAllNetworks();
110
111 // flush interface's BSS cache, so that we get BSSAdded signals for
112 // all BSSes (not just new ones since the last scan).
113 supplicant_interface_proxy_->FlushBSS(0);
114
mukesh agrawalab87ea42011-05-18 11:44:49 -0700115 LOG(INFO) << "initiating Scan.";
mukesh agrawalc7426a42011-06-03 13:04:28 -0700116 std::map<string, DBus::Variant> scan_args;
117 scan_args["Type"].writer().append_string("active");
mukesh agrawalab87ea42011-05-18 11:44:49 -0700118 // TODO(quiche) indicate scanning in UI
119 supplicant_interface_proxy_->Scan(scan_args);
120 scan_pending_ = true;
121 Device::Start();
122}
123
mukesh agrawalab87ea42011-05-18 11:44:49 -0700124void WiFi::Stop() {
125 LOG(INFO) << __func__;
mukesh agrawal31950242011-07-14 11:53:38 -0700126 // TODO(quiche): remove interface from supplicant
127 supplicant_interface_proxy_.reset(); // breaks a reference cycle
128 supplicant_process_proxy_.reset();
129 endpoint_by_bssid_.clear();
130 service_by_private_id_.clear(); // breaks reference cycles
mukesh agrawalab87ea42011-05-18 11:44:49 -0700131 Device::Stop();
mukesh agrawal31950242011-07-14 11:53:38 -0700132 // XXX anything else to do?
mukesh agrawalab87ea42011-05-18 11:44:49 -0700133}
134
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700135bool WiFi::TechnologyIs(const Device::Technology type) const {
Paul Stewartb50f0b92011-05-16 16:31:42 -0700136 return type == Device::kWifi;
137}
138
mukesh agrawalb54601c2011-06-07 17:39:22 -0700139void WiFi::BSSAdded(
140 const ::DBus::Path &BSS,
141 const std::map<string, ::DBus::Variant> &properties) {
142 // TODO(quiche): write test to verify correct behavior in the case
143 // where we get multiple BSSAdded events for a single endpoint.
144 // (old Endpoint's refcount should fall to zero, and old Endpoint
145 // should be destroyed)
146 //
147 // note: we assume that BSSIDs are unique across endpoints. this
148 // means that if an AP reuses the same BSSID for multiple SSIDs, we
149 // lose.
150 WiFiEndpointRefPtr endpoint(new WiFiEndpoint(properties));
151 endpoint_by_bssid_[endpoint->bssid_hex()] = endpoint;
152}
153
154void WiFi::ScanDone() {
155 LOG(INFO) << __func__;
156
157 // defer handling of scan result processing, because that processing
158 // may require the the registration of new D-Bus objects. and such
159 // registration can't be done in the context of a D-Bus signal
160 // handler.
161 dispatcher_->PostTask(
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700162 task_factory_.NewRunnableMethod(&WiFi::ScanDoneTask));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700163}
164
mukesh agrawal445e72c2011-06-22 11:13:50 -0700165void WiFi::ConnectTo(const WiFiService &service) {
166 std::map<string, DBus::Variant> add_network_args;
167 DBus::MessageIter writer;
168 DBus::Path network_path;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700169
mukesh agrawal445e72c2011-06-22 11:13:50 -0700170 add_network_args[kSupplicantPropertyNetworkMode].writer().
171 append_uint32(service.mode());
172 add_network_args[kSupplicantPropertyKeyMode].writer().
173 append_string(service.key_management().c_str());
174 // TODO(quiche): figure out why we can't use operator<< without the
175 // temporary variable.
176 writer = add_network_args[kSupplicantPropertySSID].writer();
177 writer << service.ssid();
178 // TODO(quiche): set scan_ssid=1, like flimflam does?
179
180 network_path =
181 supplicant_interface_proxy_->AddNetwork(add_network_args);
182 supplicant_interface_proxy_->SelectNetwork(network_path);
183 // XXX add to favorite networks list?
mukesh agrawalb54601c2011-06-07 17:39:22 -0700184}
185
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700186void WiFi::ScanDoneTask() {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700187 LOG(INFO) << __func__;
188
189 scan_pending_ = false;
190
191 // TODO(quiche): group endpoints into services, instead of creating
192 // a service for every endpoint.
193 for (EndpointMap::iterator i(endpoint_by_bssid_.begin());
194 i != endpoint_by_bssid_.end(); ++i) {
195 const WiFiEndpoint &endpoint(*(i->second));
196 string service_id_private;
197
198 service_id_private =
199 endpoint.ssid_hex() + "_" + endpoint.bssid_hex();
200 if (service_by_private_id_.find(service_id_private) ==
201 service_by_private_id_.end()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700202 LOG(INFO) << "found new endpoint. "
203 << "ssid: " << endpoint.ssid_string() << ", "
204 << "bssid: " << endpoint.bssid_string() << ", "
mukesh agrawal51a7e932011-07-27 16:18:26 -0700205 << "signal: " << endpoint.signal_strength();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700206
207 // XXX key mode should reflect endpoint params (not always use
208 // kSupplicantKeyModeNone)
mukesh agrawal31950242011-07-14 11:53:38 -0700209 WiFiServiceRefPtr service(
Chris Masone7aa5f902011-07-11 11:13:35 -0700210 new WiFiService(control_interface_,
211 dispatcher_,
Chris Masone6791a432011-07-12 13:23:19 -0700212 manager_,
Chris Masone7aa5f902011-07-11 11:13:35 -0700213 this,
Chris Masone7aa5f902011-07-11 11:13:35 -0700214 endpoint.ssid(),
215 endpoint.network_mode(),
mukesh agrawal51a7e932011-07-27 16:18:26 -0700216 kSupplicantKeyModeNone));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700217 services_.push_back(service);
218 service_by_private_id_[service_id_private] = service;
mukesh agrawal51a7e932011-07-27 16:18:26 -0700219
220 LOG(INFO) << "new service " << service->GetRpcIdentifier();
mukesh agrawalb54601c2011-06-07 17:39:22 -0700221 }
222 }
223
224 // TODO(quiche): register new services with manager
225 // TODO(quiche): unregister removed services from manager
226}
227
Paul Stewartb50f0b92011-05-16 16:31:42 -0700228} // namespace shill