blob: e7450a8bab66750e815a890ccc4bfc6ebbea0250 [file] [log] [blame]
Thieu Lee41a72d2012-02-06 20:46:51 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
mukesh agrawalb54601c2011-06-07 17:39:22 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone092df3e2011-08-22 09:41:39 -07005#include "shill/wifi_endpoint.h"
6
7#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -05008#include <base/stl_util.h>
mukesh agrawalb54601c2011-06-07 17:39:22 -07009#include <base/stringprintf.h>
10#include <base/string_number_conversions.h>
mukesh agrawal6e277772011-09-29 15:04:23 -070011#include <base/string_util.h>
Chris Masone092df3e2011-08-22 09:41:39 -070012#include <chromeos/dbus/service_constants.h>
mukesh agrawalb54601c2011-06-07 17:39:22 -070013
Thieu Le1df7f4e2012-02-10 15:21:45 -080014#include "shill/ieee80211.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080015#include "shill/proxy_factory.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070016#include "shill/scope_logger.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080017#include "shill/supplicant_bss_proxy_interface.h"
mukesh agrawal16bc1b82012-02-09 18:38:26 -080018#include "shill/wifi.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080019#include "shill/wifi_endpoint.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070020#include "shill/wpa_supplicant.h"
21
22using std::map;
23using std::set;
mukesh agrawalb54601c2011-06-07 17:39:22 -070024using std::string;
mukesh agrawal6e277772011-09-29 15:04:23 -070025using std::vector;
mukesh agrawalb54601c2011-06-07 17:39:22 -070026
27namespace shill {
28
mukesh agrawalb20776f2012-02-10 16:00:36 -080029WiFiEndpoint::WiFiEndpoint(ProxyFactory *proxy_factory,
30 const WiFiRefPtr &device,
31 const string &rpc_id,
32 const map<string, ::DBus::Variant> &properties)
33 : frequency_(0),
34 proxy_factory_(proxy_factory),
35 device_(device),
36 rpc_id_(rpc_id) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070037 // XXX will segfault on missing properties
38 ssid_ =
mukesh agrawal6e277772011-09-29 15:04:23 -070039 properties.find(wpa_supplicant::kBSSPropertySSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070040 operator std::vector<uint8_t>();
41 bssid_ =
mukesh agrawal6e277772011-09-29 15:04:23 -070042 properties.find(wpa_supplicant::kBSSPropertyBSSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070043 operator std::vector<uint8_t>();
44 signal_strength_ =
mukesh agrawal15908392011-11-16 18:29:25 +000045 properties.find(wpa_supplicant::kBSSPropertySignal)->second.
46 reader().get_int16();
Thieu Lee41a72d2012-02-06 20:46:51 +000047 map<string, ::DBus::Variant>::const_iterator it =
48 properties.find(wpa_supplicant::kBSSPropertyFrequency);
49 if (it != properties.end())
50 frequency_ = it->second.reader().get_uint16();
Thieu Le1df7f4e2012-02-10 15:21:45 -080051 physical_mode_ = DeterminePhyMode(properties, frequency_);
Chris Masone092df3e2011-08-22 09:41:39 -070052 network_mode_ = ParseMode(
mukesh agrawal6e277772011-09-29 15:04:23 -070053 properties.find(wpa_supplicant::kBSSPropertyMode)->second);
54 security_mode_ = ParseSecurity(properties);
mukesh agrawalb54601c2011-06-07 17:39:22 -070055
Chris Masone092df3e2011-08-22 09:41:39 -070056 if (network_mode_.empty()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070057 // XXX log error?
58 }
59
60 ssid_string_ = string(ssid_.begin(), ssid_.end());
mukesh agrawal16bc1b82012-02-09 18:38:26 -080061 WiFi::SanitizeSSID(&ssid_string_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070062 ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size());
63 bssid_string_ = StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
64 bssid_[0], bssid_[1], bssid_[2],
65 bssid_[3], bssid_[4], bssid_[5]);
66 bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size());
67}
68
69WiFiEndpoint::~WiFiEndpoint() {}
70
mukesh agrawalb20776f2012-02-10 16:00:36 -080071void WiFiEndpoint::Start() {
72 supplicant_bss_proxy_.reset(
73 proxy_factory_->CreateSupplicantBSSProxy(
74 this, rpc_id_, wpa_supplicant::kDBusAddr));
75}
76
77void WiFiEndpoint::PropertiesChanged(
78 const map<string, ::DBus::Variant> &properties) {
79 LOG(INFO) << __func__;
80 map<string, ::DBus::Variant>::const_iterator properties_it =
81 properties.find(wpa_supplicant::kBSSPropertySignal);
82 if (properties_it != properties.end()) {
83 signal_strength_ = properties_it->second.reader().get_int16();
Ben Chanfad4a0b2012-04-18 15:49:59 -070084 SLOG(WiFi, 2) << "WiFiEndpoint " << bssid_string_ << " signal is now "
85 << signal_strength_;
mukesh agrawalb20776f2012-02-10 16:00:36 -080086 device_->NotifyEndpointChanged(*this);
87 }
88}
89
Chris Masone092df3e2011-08-22 09:41:39 -070090// static
91uint32_t WiFiEndpoint::ModeStringToUint(const std::string &mode_string) {
92 if (mode_string == flimflam::kModeManaged)
mukesh agrawal6e277772011-09-29 15:04:23 -070093 return wpa_supplicant::kNetworkModeInfrastructureInt;
Chris Masone092df3e2011-08-22 09:41:39 -070094 else if (mode_string == flimflam::kModeAdhoc)
mukesh agrawal6e277772011-09-29 15:04:23 -070095 return wpa_supplicant::kNetworkModeAdHocInt;
Chris Masone092df3e2011-08-22 09:41:39 -070096 else
97 NOTIMPLEMENTED() << "Shill dos not support " << mode_string
98 << " mode at this time.";
99 return 0;
100}
101
mukesh agrawal6e277772011-09-29 15:04:23 -0700102const vector<uint8_t> &WiFiEndpoint::ssid() const {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700103 return ssid_;
104}
105
106const string &WiFiEndpoint::ssid_string() const {
107 return ssid_string_;
108}
109
110const string &WiFiEndpoint::ssid_hex() const {
111 return ssid_hex_;
112}
113
114const string &WiFiEndpoint::bssid_string() const {
115 return bssid_string_;
116}
117
118const string &WiFiEndpoint::bssid_hex() const {
119 return bssid_hex_;
120}
121
122int16_t WiFiEndpoint::signal_strength() const {
123 return signal_strength_;
124}
125
Thieu Lee41a72d2012-02-06 20:46:51 +0000126uint16 WiFiEndpoint::frequency() const {
127 return frequency_;
128}
129
Thieu Le1df7f4e2012-02-10 15:21:45 -0800130uint16 WiFiEndpoint::physical_mode() const {
131 return physical_mode_;
132}
133
Chris Masone092df3e2011-08-22 09:41:39 -0700134const string &WiFiEndpoint::network_mode() const {
mukesh agrawal6e277772011-09-29 15:04:23 -0700135 return network_mode_;
136}
137
138const string &WiFiEndpoint::security_mode() const {
139 return security_mode_;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700140}
141
Chris Masone092df3e2011-08-22 09:41:39 -0700142// static
mukesh agrawalb20776f2012-02-10 16:00:36 -0800143WiFiEndpoint *WiFiEndpoint::MakeOpenEndpoint(ProxyFactory *proxy_factory,
144 const WiFiRefPtr &wifi,
145 const string &ssid,
mukesh agrawale1d90e92012-02-15 17:36:08 -0800146 const string &bssid,
147 uint16 frequency,
148 int16 signal_dbm) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000149 map <string, ::DBus::Variant> args;
150 ::DBus::MessageIter writer;
151
152 writer = args[wpa_supplicant::kBSSPropertySSID].writer();
153 writer << vector<uint8_t>(ssid.begin(), ssid.end());
154
155 string bssid_nosep;
156 RemoveChars(bssid, ":", &bssid_nosep);
157 vector<uint8_t> bssid_bytes;
158 base::HexStringToBytes(bssid_nosep, &bssid_bytes);
159 writer = args[wpa_supplicant::kBSSPropertyBSSID].writer();
160 writer << bssid_bytes;
161
mukesh agrawale1d90e92012-02-15 17:36:08 -0800162 args[wpa_supplicant::kBSSPropertySignal].writer().append_int16(signal_dbm);
163 args[wpa_supplicant::kBSSPropertyFrequency].writer().append_uint16(frequency);
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000164 args[wpa_supplicant::kBSSPropertyMode].writer().append_string(
165 wpa_supplicant::kNetworkModeInfrastructure);
166 // We indicate this is an open BSS by leaving out all security properties.
167
mukesh agrawalb20776f2012-02-10 16:00:36 -0800168 return new WiFiEndpoint(
169 proxy_factory, wifi, bssid, args); // |bssid| fakes an RPC ID
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000170}
171
172// static
mukesh agrawal6e277772011-09-29 15:04:23 -0700173const char *WiFiEndpoint::ParseMode(const string &mode_string) {
174 if (mode_string == wpa_supplicant::kNetworkModeInfrastructure) {
Chris Masone092df3e2011-08-22 09:41:39 -0700175 return flimflam::kModeManaged;
mukesh agrawal6e277772011-09-29 15:04:23 -0700176 } else if (mode_string == wpa_supplicant::kNetworkModeAdHoc) {
Chris Masone092df3e2011-08-22 09:41:39 -0700177 return flimflam::kModeAdhoc;
mukesh agrawal6e277772011-09-29 15:04:23 -0700178 } else if (mode_string == wpa_supplicant::kNetworkModeAccessPoint) {
Chris Masone092df3e2011-08-22 09:41:39 -0700179 NOTREACHED() << "Shill does not support AP mode at this time.";
180 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700181 } else {
Chris Masone092df3e2011-08-22 09:41:39 -0700182 NOTREACHED() << "Unknown WiFi endpoint mode!";
183 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700184 }
185}
186
mukesh agrawal6e277772011-09-29 15:04:23 -0700187// static
188const char *WiFiEndpoint::ParseSecurity(
189 const map<string, ::DBus::Variant> &properties) {
190 set<KeyManagement> rsn_key_management_methods;
191 if (ContainsKey(properties, wpa_supplicant::kPropertyRSN)) {
192 // TODO(quiche): check type before casting
193 const map<string, ::DBus::Variant> rsn_properties(
194 properties.find(wpa_supplicant::kPropertyRSN)->second.
195 operator map<string, ::DBus::Variant>());
196 ParseKeyManagementMethods(rsn_properties, &rsn_key_management_methods);
197 }
198
199 set<KeyManagement> wpa_key_management_methods;
200 if (ContainsKey(properties, wpa_supplicant::kPropertyWPA)) {
mukesh agrawal165e6142011-11-22 02:22:56 +0000201 // TODO(quiche): check type before casting
mukesh agrawal6e277772011-09-29 15:04:23 -0700202 const map<string, ::DBus::Variant> rsn_properties(
203 properties.find(wpa_supplicant::kPropertyWPA)->second.
204 operator map<string, ::DBus::Variant>());
205 ParseKeyManagementMethods(rsn_properties, &wpa_key_management_methods);
206 }
207
208 bool wep_privacy = false;
209 if (ContainsKey(properties, wpa_supplicant::kPropertyPrivacy)) {
210 wep_privacy = properties.find(wpa_supplicant::kPropertyPrivacy)->second.
211 reader().get_bool();
212 }
213
214 if (ContainsKey(rsn_key_management_methods, kKeyManagement802_1x) ||
215 ContainsKey(wpa_key_management_methods, kKeyManagement802_1x)) {
216 return flimflam::kSecurity8021x;
217 } else if (ContainsKey(rsn_key_management_methods, kKeyManagementPSK)) {
218 return flimflam::kSecurityRsn;
219 } else if (ContainsKey(wpa_key_management_methods, kKeyManagementPSK)) {
220 return flimflam::kSecurityWpa;
221 } else if (wep_privacy) {
222 return flimflam::kSecurityWep;
223 } else {
224 return flimflam::kSecurityNone;
225 }
226}
227
228// static
229void WiFiEndpoint::ParseKeyManagementMethods(
230 const map<string, ::DBus::Variant> &security_method_properties,
231 set<KeyManagement> *key_management_methods) {
232 if (!ContainsKey(security_method_properties,
233 wpa_supplicant::kSecurityMethodPropertyKeyManagement)) {
234 return;
235 }
236
237 // TODO(quiche): check type before cast
238 const vector<string> key_management_vec =
239 security_method_properties.
240 find(wpa_supplicant::kSecurityMethodPropertyKeyManagement)->second.
241 operator vector<string>();
242 for (vector<string>::const_iterator it = key_management_vec.begin();
243 it != key_management_vec.end();
244 ++it) {
245 if (EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixEAP, true)) {
246 key_management_methods->insert(kKeyManagement802_1x);
247 } else if (
248 EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixPSK, true)) {
249 key_management_methods->insert(kKeyManagementPSK);
250 }
251 }
252}
253
Thieu Le1df7f4e2012-02-10 15:21:45 -0800254// static
255Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyMode(
256 const map<string, ::DBus::Variant> &properties, uint16 frequency) {
257 uint32_t max_rate = 0;
258 map<string, ::DBus::Variant>::const_iterator it =
259 properties.find(wpa_supplicant::kBSSPropertyRates);
260 if (it != properties.end()) {
261 vector<uint32_t> rates = it->second.operator vector<uint32_t>();
262 if (rates.size() > 0)
263 max_rate = rates[0]; // Rates are sorted in descending order
264 }
265
266 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
267 it = properties.find(wpa_supplicant::kBSSPropertyIEs);
268 if (it != properties.end()) {
269 phy_mode = ParseIEsForPhyMode(it->second.operator vector<uint8_t>());
270 if (phy_mode != Metrics::kWiFiNetworkPhyModeUndef)
271 return phy_mode;
272 }
273
274 if (frequency < 3000) {
275 // 2.4GHz legacy, check for tx rate for 11b-only
276 // (note 22M is valid)
277 if (max_rate < 24000000)
278 phy_mode = Metrics::kWiFiNetworkPhyMode11b;
279 else
280 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
281 } else {
282 phy_mode = Metrics::kWiFiNetworkPhyMode11a;
283 }
284
285 return phy_mode;
286}
287
288// static
289Metrics::WiFiNetworkPhyMode WiFiEndpoint::ParseIEsForPhyMode(
290 const vector<uint8_t> &ies) {
291 // Format of an information element:
292 // 1 1 3 1 - 252
293 // +------+--------+------------+----------------+
294 // | Type | Length | OUI | Data |
295 // +------+--------+------------+----------------+
296 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
297 vector<uint8_t>::const_iterator it;
298 for (it = ies.begin();
299 it + 1 < ies.end(); // +1 to ensure Length field is in valid memory
300 it += 2 + *(it + 1)) {
301 if (*it == IEEE_80211::kElemIdErp) {
302 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
303 continue; // NB: Continue to check for HT
304 }
305 if (*it == IEEE_80211::kElemIdHTCap || *it == IEEE_80211::kElemIdHTInfo) {
306 phy_mode = Metrics::kWiFiNetworkPhyMode11n;
307 break;
308 }
309 }
310
311 return phy_mode;
312}
313
mukesh agrawalb54601c2011-06-07 17:39:22 -0700314} // namespace shill