blob: e78d6cdf9f5a3b388ee68ea8fb9b6618fa7df81c [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>
mukesh agrawal6e277772011-09-29 15:04:23 -07008#include <base/stl_util-inl.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"
16#include "shill/supplicant_bss_proxy_interface.h"
mukesh agrawal16bc1b82012-02-09 18:38:26 -080017#include "shill/wifi.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080018#include "shill/wifi_endpoint.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070019#include "shill/wpa_supplicant.h"
20
21using std::map;
22using std::set;
mukesh agrawalb54601c2011-06-07 17:39:22 -070023using std::string;
mukesh agrawal6e277772011-09-29 15:04:23 -070024using std::vector;
mukesh agrawalb54601c2011-06-07 17:39:22 -070025
26namespace shill {
27
mukesh agrawalb20776f2012-02-10 16:00:36 -080028WiFiEndpoint::WiFiEndpoint(ProxyFactory *proxy_factory,
29 const WiFiRefPtr &device,
30 const string &rpc_id,
31 const map<string, ::DBus::Variant> &properties)
32 : frequency_(0),
33 proxy_factory_(proxy_factory),
34 device_(device),
35 rpc_id_(rpc_id) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070036 // XXX will segfault on missing properties
37 ssid_ =
mukesh agrawal6e277772011-09-29 15:04:23 -070038 properties.find(wpa_supplicant::kBSSPropertySSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070039 operator std::vector<uint8_t>();
40 bssid_ =
mukesh agrawal6e277772011-09-29 15:04:23 -070041 properties.find(wpa_supplicant::kBSSPropertyBSSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070042 operator std::vector<uint8_t>();
43 signal_strength_ =
mukesh agrawal15908392011-11-16 18:29:25 +000044 properties.find(wpa_supplicant::kBSSPropertySignal)->second.
45 reader().get_int16();
Thieu Lee41a72d2012-02-06 20:46:51 +000046 map<string, ::DBus::Variant>::const_iterator it =
47 properties.find(wpa_supplicant::kBSSPropertyFrequency);
48 if (it != properties.end())
49 frequency_ = it->second.reader().get_uint16();
Thieu Le1df7f4e2012-02-10 15:21:45 -080050 physical_mode_ = DeterminePhyMode(properties, frequency_);
Chris Masone092df3e2011-08-22 09:41:39 -070051 network_mode_ = ParseMode(
mukesh agrawal6e277772011-09-29 15:04:23 -070052 properties.find(wpa_supplicant::kBSSPropertyMode)->second);
53 security_mode_ = ParseSecurity(properties);
mukesh agrawalb54601c2011-06-07 17:39:22 -070054
Chris Masone092df3e2011-08-22 09:41:39 -070055 if (network_mode_.empty()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070056 // XXX log error?
57 }
58
59 ssid_string_ = string(ssid_.begin(), ssid_.end());
mukesh agrawal16bc1b82012-02-09 18:38:26 -080060 WiFi::SanitizeSSID(&ssid_string_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070061 ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size());
62 bssid_string_ = StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
63 bssid_[0], bssid_[1], bssid_[2],
64 bssid_[3], bssid_[4], bssid_[5]);
65 bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size());
66}
67
68WiFiEndpoint::~WiFiEndpoint() {}
69
mukesh agrawalb20776f2012-02-10 16:00:36 -080070void WiFiEndpoint::Start() {
71 supplicant_bss_proxy_.reset(
72 proxy_factory_->CreateSupplicantBSSProxy(
73 this, rpc_id_, wpa_supplicant::kDBusAddr));
74}
75
76void WiFiEndpoint::PropertiesChanged(
77 const map<string, ::DBus::Variant> &properties) {
78 LOG(INFO) << __func__;
79 map<string, ::DBus::Variant>::const_iterator properties_it =
80 properties.find(wpa_supplicant::kBSSPropertySignal);
81 if (properties_it != properties.end()) {
82 signal_strength_ = properties_it->second.reader().get_int16();
83 VLOG(2) << "WiFiEndpoint " << bssid_string_ << " signal is now "
84 << signal_strength_;
85 device_->NotifyEndpointChanged(*this);
86 }
87}
88
Chris Masone092df3e2011-08-22 09:41:39 -070089// static
90uint32_t WiFiEndpoint::ModeStringToUint(const std::string &mode_string) {
91 if (mode_string == flimflam::kModeManaged)
mukesh agrawal6e277772011-09-29 15:04:23 -070092 return wpa_supplicant::kNetworkModeInfrastructureInt;
Chris Masone092df3e2011-08-22 09:41:39 -070093 else if (mode_string == flimflam::kModeAdhoc)
mukesh agrawal6e277772011-09-29 15:04:23 -070094 return wpa_supplicant::kNetworkModeAdHocInt;
Chris Masone092df3e2011-08-22 09:41:39 -070095 else
96 NOTIMPLEMENTED() << "Shill dos not support " << mode_string
97 << " mode at this time.";
98 return 0;
99}
100
mukesh agrawal6e277772011-09-29 15:04:23 -0700101const vector<uint8_t> &WiFiEndpoint::ssid() const {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700102 return ssid_;
103}
104
105const string &WiFiEndpoint::ssid_string() const {
106 return ssid_string_;
107}
108
109const string &WiFiEndpoint::ssid_hex() const {
110 return ssid_hex_;
111}
112
113const string &WiFiEndpoint::bssid_string() const {
114 return bssid_string_;
115}
116
117const string &WiFiEndpoint::bssid_hex() const {
118 return bssid_hex_;
119}
120
121int16_t WiFiEndpoint::signal_strength() const {
122 return signal_strength_;
123}
124
Thieu Lee41a72d2012-02-06 20:46:51 +0000125uint16 WiFiEndpoint::frequency() const {
126 return frequency_;
127}
128
Thieu Le1df7f4e2012-02-10 15:21:45 -0800129uint16 WiFiEndpoint::physical_mode() const {
130 return physical_mode_;
131}
132
Chris Masone092df3e2011-08-22 09:41:39 -0700133const string &WiFiEndpoint::network_mode() const {
mukesh agrawal6e277772011-09-29 15:04:23 -0700134 return network_mode_;
135}
136
137const string &WiFiEndpoint::security_mode() const {
138 return security_mode_;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700139}
140
Chris Masone092df3e2011-08-22 09:41:39 -0700141// static
mukesh agrawalb20776f2012-02-10 16:00:36 -0800142WiFiEndpoint *WiFiEndpoint::MakeOpenEndpoint(ProxyFactory *proxy_factory,
143 const WiFiRefPtr &wifi,
144 const string &ssid,
145 const string &bssid) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000146 map <string, ::DBus::Variant> args;
147 ::DBus::MessageIter writer;
148
149 writer = args[wpa_supplicant::kBSSPropertySSID].writer();
150 writer << vector<uint8_t>(ssid.begin(), ssid.end());
151
152 string bssid_nosep;
153 RemoveChars(bssid, ":", &bssid_nosep);
154 vector<uint8_t> bssid_bytes;
155 base::HexStringToBytes(bssid_nosep, &bssid_bytes);
156 writer = args[wpa_supplicant::kBSSPropertyBSSID].writer();
157 writer << bssid_bytes;
158
159 args[wpa_supplicant::kBSSPropertySignal].writer().append_int16(0);
160 args[wpa_supplicant::kBSSPropertyMode].writer().append_string(
161 wpa_supplicant::kNetworkModeInfrastructure);
162 // We indicate this is an open BSS by leaving out all security properties.
163
mukesh agrawalb20776f2012-02-10 16:00:36 -0800164 return new WiFiEndpoint(
165 proxy_factory, wifi, bssid, args); // |bssid| fakes an RPC ID
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000166}
167
168// static
mukesh agrawal6e277772011-09-29 15:04:23 -0700169const char *WiFiEndpoint::ParseMode(const string &mode_string) {
170 if (mode_string == wpa_supplicant::kNetworkModeInfrastructure) {
Chris Masone092df3e2011-08-22 09:41:39 -0700171 return flimflam::kModeManaged;
mukesh agrawal6e277772011-09-29 15:04:23 -0700172 } else if (mode_string == wpa_supplicant::kNetworkModeAdHoc) {
Chris Masone092df3e2011-08-22 09:41:39 -0700173 return flimflam::kModeAdhoc;
mukesh agrawal6e277772011-09-29 15:04:23 -0700174 } else if (mode_string == wpa_supplicant::kNetworkModeAccessPoint) {
Chris Masone092df3e2011-08-22 09:41:39 -0700175 NOTREACHED() << "Shill does not support AP mode at this time.";
176 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700177 } else {
Chris Masone092df3e2011-08-22 09:41:39 -0700178 NOTREACHED() << "Unknown WiFi endpoint mode!";
179 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700180 }
181}
182
mukesh agrawal6e277772011-09-29 15:04:23 -0700183// static
184const char *WiFiEndpoint::ParseSecurity(
185 const map<string, ::DBus::Variant> &properties) {
186 set<KeyManagement> rsn_key_management_methods;
187 if (ContainsKey(properties, wpa_supplicant::kPropertyRSN)) {
188 // TODO(quiche): check type before casting
189 const map<string, ::DBus::Variant> rsn_properties(
190 properties.find(wpa_supplicant::kPropertyRSN)->second.
191 operator map<string, ::DBus::Variant>());
192 ParseKeyManagementMethods(rsn_properties, &rsn_key_management_methods);
193 }
194
195 set<KeyManagement> wpa_key_management_methods;
196 if (ContainsKey(properties, wpa_supplicant::kPropertyWPA)) {
mukesh agrawal165e6142011-11-22 02:22:56 +0000197 // TODO(quiche): check type before casting
mukesh agrawal6e277772011-09-29 15:04:23 -0700198 const map<string, ::DBus::Variant> rsn_properties(
199 properties.find(wpa_supplicant::kPropertyWPA)->second.
200 operator map<string, ::DBus::Variant>());
201 ParseKeyManagementMethods(rsn_properties, &wpa_key_management_methods);
202 }
203
204 bool wep_privacy = false;
205 if (ContainsKey(properties, wpa_supplicant::kPropertyPrivacy)) {
206 wep_privacy = properties.find(wpa_supplicant::kPropertyPrivacy)->second.
207 reader().get_bool();
208 }
209
210 if (ContainsKey(rsn_key_management_methods, kKeyManagement802_1x) ||
211 ContainsKey(wpa_key_management_methods, kKeyManagement802_1x)) {
212 return flimflam::kSecurity8021x;
213 } else if (ContainsKey(rsn_key_management_methods, kKeyManagementPSK)) {
214 return flimflam::kSecurityRsn;
215 } else if (ContainsKey(wpa_key_management_methods, kKeyManagementPSK)) {
216 return flimflam::kSecurityWpa;
217 } else if (wep_privacy) {
218 return flimflam::kSecurityWep;
219 } else {
220 return flimflam::kSecurityNone;
221 }
222}
223
224// static
225void WiFiEndpoint::ParseKeyManagementMethods(
226 const map<string, ::DBus::Variant> &security_method_properties,
227 set<KeyManagement> *key_management_methods) {
228 if (!ContainsKey(security_method_properties,
229 wpa_supplicant::kSecurityMethodPropertyKeyManagement)) {
230 return;
231 }
232
233 // TODO(quiche): check type before cast
234 const vector<string> key_management_vec =
235 security_method_properties.
236 find(wpa_supplicant::kSecurityMethodPropertyKeyManagement)->second.
237 operator vector<string>();
238 for (vector<string>::const_iterator it = key_management_vec.begin();
239 it != key_management_vec.end();
240 ++it) {
241 if (EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixEAP, true)) {
242 key_management_methods->insert(kKeyManagement802_1x);
243 } else if (
244 EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixPSK, true)) {
245 key_management_methods->insert(kKeyManagementPSK);
246 }
247 }
248}
249
Thieu Le1df7f4e2012-02-10 15:21:45 -0800250// static
251Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyMode(
252 const map<string, ::DBus::Variant> &properties, uint16 frequency) {
253 uint32_t max_rate = 0;
254 map<string, ::DBus::Variant>::const_iterator it =
255 properties.find(wpa_supplicant::kBSSPropertyRates);
256 if (it != properties.end()) {
257 vector<uint32_t> rates = it->second.operator vector<uint32_t>();
258 if (rates.size() > 0)
259 max_rate = rates[0]; // Rates are sorted in descending order
260 }
261
262 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
263 it = properties.find(wpa_supplicant::kBSSPropertyIEs);
264 if (it != properties.end()) {
265 phy_mode = ParseIEsForPhyMode(it->second.operator vector<uint8_t>());
266 if (phy_mode != Metrics::kWiFiNetworkPhyModeUndef)
267 return phy_mode;
268 }
269
270 if (frequency < 3000) {
271 // 2.4GHz legacy, check for tx rate for 11b-only
272 // (note 22M is valid)
273 if (max_rate < 24000000)
274 phy_mode = Metrics::kWiFiNetworkPhyMode11b;
275 else
276 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
277 } else {
278 phy_mode = Metrics::kWiFiNetworkPhyMode11a;
279 }
280
281 return phy_mode;
282}
283
284// static
285Metrics::WiFiNetworkPhyMode WiFiEndpoint::ParseIEsForPhyMode(
286 const vector<uint8_t> &ies) {
287 // Format of an information element:
288 // 1 1 3 1 - 252
289 // +------+--------+------------+----------------+
290 // | Type | Length | OUI | Data |
291 // +------+--------+------------+----------------+
292 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
293 vector<uint8_t>::const_iterator it;
294 for (it = ies.begin();
295 it + 1 < ies.end(); // +1 to ensure Length field is in valid memory
296 it += 2 + *(it + 1)) {
297 if (*it == IEEE_80211::kElemIdErp) {
298 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
299 continue; // NB: Continue to check for HT
300 }
301 if (*it == IEEE_80211::kElemIdHTCap || *it == IEEE_80211::kElemIdHTInfo) {
302 phy_mode = Metrics::kWiFiNetworkPhyMode11n;
303 break;
304 }
305 }
306
307 return phy_mode;
308}
309
mukesh agrawalb54601c2011-06-07 17:39:22 -0700310} // namespace shill