blob: dbe2c322fccd0b314e62717693fbdc0c0fe18a01 [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"
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,
mukesh agrawale1d90e92012-02-15 17:36:08 -0800145 const string &bssid,
146 uint16 frequency,
147 int16 signal_dbm) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000148 map <string, ::DBus::Variant> args;
149 ::DBus::MessageIter writer;
150
151 writer = args[wpa_supplicant::kBSSPropertySSID].writer();
152 writer << vector<uint8_t>(ssid.begin(), ssid.end());
153
154 string bssid_nosep;
155 RemoveChars(bssid, ":", &bssid_nosep);
156 vector<uint8_t> bssid_bytes;
157 base::HexStringToBytes(bssid_nosep, &bssid_bytes);
158 writer = args[wpa_supplicant::kBSSPropertyBSSID].writer();
159 writer << bssid_bytes;
160
mukesh agrawale1d90e92012-02-15 17:36:08 -0800161 args[wpa_supplicant::kBSSPropertySignal].writer().append_int16(signal_dbm);
162 args[wpa_supplicant::kBSSPropertyFrequency].writer().append_uint16(frequency);
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000163 args[wpa_supplicant::kBSSPropertyMode].writer().append_string(
164 wpa_supplicant::kNetworkModeInfrastructure);
165 // We indicate this is an open BSS by leaving out all security properties.
166
mukesh agrawalb20776f2012-02-10 16:00:36 -0800167 return new WiFiEndpoint(
168 proxy_factory, wifi, bssid, args); // |bssid| fakes an RPC ID
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000169}
170
171// static
mukesh agrawal6e277772011-09-29 15:04:23 -0700172const char *WiFiEndpoint::ParseMode(const string &mode_string) {
173 if (mode_string == wpa_supplicant::kNetworkModeInfrastructure) {
Chris Masone092df3e2011-08-22 09:41:39 -0700174 return flimflam::kModeManaged;
mukesh agrawal6e277772011-09-29 15:04:23 -0700175 } else if (mode_string == wpa_supplicant::kNetworkModeAdHoc) {
Chris Masone092df3e2011-08-22 09:41:39 -0700176 return flimflam::kModeAdhoc;
mukesh agrawal6e277772011-09-29 15:04:23 -0700177 } else if (mode_string == wpa_supplicant::kNetworkModeAccessPoint) {
Chris Masone092df3e2011-08-22 09:41:39 -0700178 NOTREACHED() << "Shill does not support AP mode at this time.";
179 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700180 } else {
Chris Masone092df3e2011-08-22 09:41:39 -0700181 NOTREACHED() << "Unknown WiFi endpoint mode!";
182 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700183 }
184}
185
mukesh agrawal6e277772011-09-29 15:04:23 -0700186// static
187const char *WiFiEndpoint::ParseSecurity(
188 const map<string, ::DBus::Variant> &properties) {
189 set<KeyManagement> rsn_key_management_methods;
190 if (ContainsKey(properties, wpa_supplicant::kPropertyRSN)) {
191 // TODO(quiche): check type before casting
192 const map<string, ::DBus::Variant> rsn_properties(
193 properties.find(wpa_supplicant::kPropertyRSN)->second.
194 operator map<string, ::DBus::Variant>());
195 ParseKeyManagementMethods(rsn_properties, &rsn_key_management_methods);
196 }
197
198 set<KeyManagement> wpa_key_management_methods;
199 if (ContainsKey(properties, wpa_supplicant::kPropertyWPA)) {
mukesh agrawal165e6142011-11-22 02:22:56 +0000200 // TODO(quiche): check type before casting
mukesh agrawal6e277772011-09-29 15:04:23 -0700201 const map<string, ::DBus::Variant> rsn_properties(
202 properties.find(wpa_supplicant::kPropertyWPA)->second.
203 operator map<string, ::DBus::Variant>());
204 ParseKeyManagementMethods(rsn_properties, &wpa_key_management_methods);
205 }
206
207 bool wep_privacy = false;
208 if (ContainsKey(properties, wpa_supplicant::kPropertyPrivacy)) {
209 wep_privacy = properties.find(wpa_supplicant::kPropertyPrivacy)->second.
210 reader().get_bool();
211 }
212
213 if (ContainsKey(rsn_key_management_methods, kKeyManagement802_1x) ||
214 ContainsKey(wpa_key_management_methods, kKeyManagement802_1x)) {
215 return flimflam::kSecurity8021x;
216 } else if (ContainsKey(rsn_key_management_methods, kKeyManagementPSK)) {
217 return flimflam::kSecurityRsn;
218 } else if (ContainsKey(wpa_key_management_methods, kKeyManagementPSK)) {
219 return flimflam::kSecurityWpa;
220 } else if (wep_privacy) {
221 return flimflam::kSecurityWep;
222 } else {
223 return flimflam::kSecurityNone;
224 }
225}
226
227// static
228void WiFiEndpoint::ParseKeyManagementMethods(
229 const map<string, ::DBus::Variant> &security_method_properties,
230 set<KeyManagement> *key_management_methods) {
231 if (!ContainsKey(security_method_properties,
232 wpa_supplicant::kSecurityMethodPropertyKeyManagement)) {
233 return;
234 }
235
236 // TODO(quiche): check type before cast
237 const vector<string> key_management_vec =
238 security_method_properties.
239 find(wpa_supplicant::kSecurityMethodPropertyKeyManagement)->second.
240 operator vector<string>();
241 for (vector<string>::const_iterator it = key_management_vec.begin();
242 it != key_management_vec.end();
243 ++it) {
244 if (EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixEAP, true)) {
245 key_management_methods->insert(kKeyManagement802_1x);
246 } else if (
247 EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixPSK, true)) {
248 key_management_methods->insert(kKeyManagementPSK);
249 }
250 }
251}
252
Thieu Le1df7f4e2012-02-10 15:21:45 -0800253// static
254Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyMode(
255 const map<string, ::DBus::Variant> &properties, uint16 frequency) {
256 uint32_t max_rate = 0;
257 map<string, ::DBus::Variant>::const_iterator it =
258 properties.find(wpa_supplicant::kBSSPropertyRates);
259 if (it != properties.end()) {
260 vector<uint32_t> rates = it->second.operator vector<uint32_t>();
261 if (rates.size() > 0)
262 max_rate = rates[0]; // Rates are sorted in descending order
263 }
264
265 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
266 it = properties.find(wpa_supplicant::kBSSPropertyIEs);
267 if (it != properties.end()) {
268 phy_mode = ParseIEsForPhyMode(it->second.operator vector<uint8_t>());
269 if (phy_mode != Metrics::kWiFiNetworkPhyModeUndef)
270 return phy_mode;
271 }
272
273 if (frequency < 3000) {
274 // 2.4GHz legacy, check for tx rate for 11b-only
275 // (note 22M is valid)
276 if (max_rate < 24000000)
277 phy_mode = Metrics::kWiFiNetworkPhyMode11b;
278 else
279 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
280 } else {
281 phy_mode = Metrics::kWiFiNetworkPhyMode11a;
282 }
283
284 return phy_mode;
285}
286
287// static
288Metrics::WiFiNetworkPhyMode WiFiEndpoint::ParseIEsForPhyMode(
289 const vector<uint8_t> &ies) {
290 // Format of an information element:
291 // 1 1 3 1 - 252
292 // +------+--------+------------+----------------+
293 // | Type | Length | OUI | Data |
294 // +------+--------+------------+----------------+
295 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
296 vector<uint8_t>::const_iterator it;
297 for (it = ies.begin();
298 it + 1 < ies.end(); // +1 to ensure Length field is in valid memory
299 it += 2 + *(it + 1)) {
300 if (*it == IEEE_80211::kElemIdErp) {
301 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
302 continue; // NB: Continue to check for HT
303 }
304 if (*it == IEEE_80211::kElemIdHTCap || *it == IEEE_80211::kElemIdHTInfo) {
305 phy_mode = Metrics::kWiFiNetworkPhyMode11n;
306 break;
307 }
308 }
309
310 return phy_mode;
311}
312
mukesh agrawalb54601c2011-06-07 17:39:22 -0700313} // namespace shill