blob: ae17d6683e39004ff90621c6c912e8f654c20fe9 [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
Paul Stewart72b2fdc2012-06-02 08:58:51 -07007#include <algorithm>
8
Eric Shienbrood3e20a232012-02-16 11:35:56 -05009#include <base/stl_util.h>
mukesh agrawalb54601c2011-06-07 17:39:22 -070010#include <base/stringprintf.h>
11#include <base/string_number_conversions.h>
mukesh agrawal6e277772011-09-29 15:04:23 -070012#include <base/string_util.h>
Chris Masone092df3e2011-08-22 09:41:39 -070013#include <chromeos/dbus/service_constants.h>
mukesh agrawalb54601c2011-06-07 17:39:22 -070014
Thieu Le1df7f4e2012-02-10 15:21:45 -080015#include "shill/ieee80211.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070016#include "shill/logging.h"
mukesh agrawalf6b32092013-04-10 15:49:55 -070017#include "shill/metrics.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080018#include "shill/proxy_factory.h"
19#include "shill/supplicant_bss_proxy_interface.h"
Paul Stewartfa11e282013-12-02 22:04:25 -080020#include "shill/tethering.h"
mukesh agrawal16bc1b82012-02-09 18:38:26 -080021#include "shill/wifi.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080022#include "shill/wifi_endpoint.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070023#include "shill/wpa_supplicant.h"
24
25using std::map;
26using std::set;
mukesh agrawalb54601c2011-06-07 17:39:22 -070027using std::string;
mukesh agrawal6e277772011-09-29 15:04:23 -070028using std::vector;
mukesh agrawalb54601c2011-06-07 17:39:22 -070029
30namespace shill {
31
Paul Stewartc67f0bd2013-12-06 12:14:50 -080032// static
33const size_t WiFiEndpoint::kBSSIDLength = 6U;
34
mukesh agrawalb20776f2012-02-10 16:00:36 -080035WiFiEndpoint::WiFiEndpoint(ProxyFactory *proxy_factory,
36 const WiFiRefPtr &device,
37 const string &rpc_id,
38 const map<string, ::DBus::Variant> &properties)
39 : frequency_(0),
mukesh agrawalf6b32092013-04-10 15:49:55 -070040 physical_mode_(Metrics::kWiFiNetworkPhyModeUndef),
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080041 ieee80211w_required_(false),
mukesh agrawalb20776f2012-02-10 16:00:36 -080042 proxy_factory_(proxy_factory),
43 device_(device),
44 rpc_id_(rpc_id) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070045 // XXX will segfault on missing properties
46 ssid_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070047 properties.find(WPASupplicant::kBSSPropertySSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070048 operator std::vector<uint8_t>();
49 bssid_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070050 properties.find(WPASupplicant::kBSSPropertyBSSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070051 operator std::vector<uint8_t>();
52 signal_strength_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070053 properties.find(WPASupplicant::kBSSPropertySignal)->second.
mukesh agrawal15908392011-11-16 18:29:25 +000054 reader().get_int16();
Thieu Lee41a72d2012-02-06 20:46:51 +000055 map<string, ::DBus::Variant>::const_iterator it =
Paul Stewart0654ece2013-03-26 15:21:26 -070056 properties.find(WPASupplicant::kBSSPropertyFrequency);
Thieu Lee41a72d2012-02-06 20:46:51 +000057 if (it != properties.end())
58 frequency_ = it->second.reader().get_uint16();
Paul Stewart72b2fdc2012-06-02 08:58:51 -070059
60 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080061 if (!ParseIEs(properties, &phy_mode, &vendor_information_,
Paul Stewartbdbd3c32013-04-17 09:47:21 -070062 &ieee80211w_required_, &country_code_)) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -070063 phy_mode = DeterminePhyModeFromFrequency(properties, frequency_);
64 }
65 physical_mode_ = phy_mode;
66
Chris Masone092df3e2011-08-22 09:41:39 -070067 network_mode_ = ParseMode(
Paul Stewart0654ece2013-03-26 15:21:26 -070068 properties.find(WPASupplicant::kBSSPropertyMode)->second);
Paul Stewartaffc0552013-03-25 07:50:15 -070069 set_security_mode(ParseSecurity(properties, &security_flags_));
Paul Stewart0654ece2013-03-26 15:21:26 -070070 has_rsn_property_ = ContainsKey(properties, WPASupplicant::kPropertyRSN);
71 has_wpa_property_ = ContainsKey(properties, WPASupplicant::kPropertyWPA);
mukesh agrawalb54601c2011-06-07 17:39:22 -070072
Chris Masone092df3e2011-08-22 09:41:39 -070073 if (network_mode_.empty()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070074 // XXX log error?
75 }
76
77 ssid_string_ = string(ssid_.begin(), ssid_.end());
mukesh agrawal16bc1b82012-02-09 18:38:26 -080078 WiFi::SanitizeSSID(&ssid_string_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070079 ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size());
Paul Stewartc67f0bd2013-12-06 12:14:50 -080080 bssid_string_ = MakeStringFromHardwareAddress(bssid_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070081 bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size());
Paul Stewartfa11e282013-12-02 22:04:25 -080082
83 CheckForTetheringSignature();
mukesh agrawalb54601c2011-06-07 17:39:22 -070084}
85
86WiFiEndpoint::~WiFiEndpoint() {}
87
mukesh agrawalb20776f2012-02-10 16:00:36 -080088void WiFiEndpoint::Start() {
89 supplicant_bss_proxy_.reset(
90 proxy_factory_->CreateSupplicantBSSProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -070091 this, rpc_id_, WPASupplicant::kDBusAddr));
mukesh agrawalb20776f2012-02-10 16:00:36 -080092}
93
94void WiFiEndpoint::PropertiesChanged(
95 const map<string, ::DBus::Variant> &properties) {
Darin Petkov3abc3be2012-06-27 10:48:23 +020096 SLOG(WiFi, 2) << __func__;
Paul Stewartaffc0552013-03-25 07:50:15 -070097 bool should_notify = false;
mukesh agrawalb20776f2012-02-10 16:00:36 -080098 map<string, ::DBus::Variant>::const_iterator properties_it =
Paul Stewart0654ece2013-03-26 15:21:26 -070099 properties.find(WPASupplicant::kBSSPropertySignal);
mukesh agrawalb20776f2012-02-10 16:00:36 -0800100 if (properties_it != properties.end()) {
101 signal_strength_ = properties_it->second.reader().get_int16();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700102 SLOG(WiFi, 2) << "WiFiEndpoint " << bssid_string_ << " signal is now "
103 << signal_strength_;
Paul Stewartaffc0552013-03-25 07:50:15 -0700104 should_notify = true;
105 }
106
107 properties_it = properties.find(WPASupplicant::kBSSPropertyMode);
108 if (properties_it != properties.end()) {
109 string new_mode = ParseMode(properties_it->second);
110 if (new_mode != network_mode_) {
111 network_mode_ = new_mode;
112 SLOG(WiFi, 2) << "WiFiEndpoint " << bssid_string_ << " mode is now "
113 << network_mode_;
114 should_notify = true;
115 }
116 }
117
118 const char *new_security_mode = ParseSecurity(properties, &security_flags_);
119 if (new_security_mode != security_mode()) {
120 set_security_mode(new_security_mode);
121 SLOG(WiFi, 2) << "WiFiEndpoint " << bssid_string_ << " security is now "
122 << security_mode();
123 should_notify = true;
124 }
125
126 if (should_notify) {
Paul Stewart3c504012013-01-17 17:49:58 -0800127 device_->NotifyEndpointChanged(this);
mukesh agrawalb20776f2012-02-10 16:00:36 -0800128 }
129}
130
Paul Stewart7cd45722013-08-12 14:50:14 -0700131void WiFiEndpoint::UpdateSignalStrength(int16 strength) {
132 if (signal_strength_ == strength ) {
133 return;
134 }
135
136 SLOG(WiFi, 2) << __func__ << ": signal strength "
137 << signal_strength_ << " -> " << strength;
138 signal_strength_ = strength;
139 device_->NotifyEndpointChanged(this);
140}
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700141
142map<string, string> WiFiEndpoint::GetVendorInformation() const {
143 map<string, string> vendor_information;
144 if (!vendor_information_.wps_manufacturer.empty()) {
145 vendor_information[kVendorWPSManufacturerProperty] =
146 vendor_information_.wps_manufacturer;
147 }
148 if (!vendor_information_.wps_model_name.empty()) {
149 vendor_information[kVendorWPSModelNameProperty] =
150 vendor_information_.wps_model_name;
151 }
152 if (!vendor_information_.wps_model_number.empty()) {
153 vendor_information[kVendorWPSModelNumberProperty] =
154 vendor_information_.wps_model_number;
155 }
156 if (!vendor_information_.wps_device_name.empty()) {
157 vendor_information[kVendorWPSDeviceNameProperty] =
158 vendor_information_.wps_device_name;
159 }
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800160 if (!vendor_information_.oui_set.empty()) {
161 vector<string> oui_vector;
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700162 set<uint32_t>::const_iterator it;
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800163 for (it = vendor_information_.oui_set.begin();
164 it != vendor_information_.oui_set.end();
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700165 ++it) {
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800166 oui_vector.push_back(
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700167 StringPrintf("%02x-%02x-%02x",
168 *it >> 16, (*it >> 8) & 0xff, *it & 0xff));
169 }
170 vendor_information[kVendorOUIListProperty] =
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800171 JoinString(oui_vector, ' ');
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700172 }
173 return vendor_information;
174}
175
Chris Masone092df3e2011-08-22 09:41:39 -0700176// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700177uint32_t WiFiEndpoint::ModeStringToUint(const string &mode_string) {
Ben Chanf024ef42013-09-20 14:21:38 -0700178 if (mode_string == kModeManaged)
Paul Stewart0654ece2013-03-26 15:21:26 -0700179 return WPASupplicant::kNetworkModeInfrastructureInt;
Ben Chanf024ef42013-09-20 14:21:38 -0700180 else if (mode_string == kModeAdhoc)
Paul Stewart0654ece2013-03-26 15:21:26 -0700181 return WPASupplicant::kNetworkModeAdHocInt;
Chris Masone092df3e2011-08-22 09:41:39 -0700182 else
183 NOTIMPLEMENTED() << "Shill dos not support " << mode_string
184 << " mode at this time.";
185 return 0;
186}
187
mukesh agrawal6e277772011-09-29 15:04:23 -0700188const vector<uint8_t> &WiFiEndpoint::ssid() const {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700189 return ssid_;
190}
191
192const string &WiFiEndpoint::ssid_string() const {
193 return ssid_string_;
194}
195
196const string &WiFiEndpoint::ssid_hex() const {
197 return ssid_hex_;
198}
199
200const string &WiFiEndpoint::bssid_string() const {
201 return bssid_string_;
202}
203
204const string &WiFiEndpoint::bssid_hex() const {
205 return bssid_hex_;
206}
207
Paul Stewartbdbd3c32013-04-17 09:47:21 -0700208const string &WiFiEndpoint::country_code() const {
209 return country_code_;
210}
211
Paul Stewart3c504012013-01-17 17:49:58 -0800212const WiFiRefPtr &WiFiEndpoint::device() const {
213 return device_;
214}
215
mukesh agrawalb54601c2011-06-07 17:39:22 -0700216int16_t WiFiEndpoint::signal_strength() const {
217 return signal_strength_;
218}
219
Thieu Lee41a72d2012-02-06 20:46:51 +0000220uint16 WiFiEndpoint::frequency() const {
221 return frequency_;
222}
223
Thieu Le1df7f4e2012-02-10 15:21:45 -0800224uint16 WiFiEndpoint::physical_mode() const {
225 return physical_mode_;
226}
227
Chris Masone092df3e2011-08-22 09:41:39 -0700228const string &WiFiEndpoint::network_mode() const {
mukesh agrawal6e277772011-09-29 15:04:23 -0700229 return network_mode_;
230}
231
232const string &WiFiEndpoint::security_mode() const {
233 return security_mode_;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700234}
235
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800236bool WiFiEndpoint::ieee80211w_required() const {
237 return ieee80211w_required_;
238}
239
mukesh agrawal43970a22013-02-15 16:00:07 -0800240bool WiFiEndpoint::has_rsn_property() const {
241 return has_rsn_property_;
242}
243
244bool WiFiEndpoint::has_wpa_property() const {
245 return has_wpa_property_;
246}
247
Paul Stewartfa11e282013-12-02 22:04:25 -0800248bool WiFiEndpoint::has_tethering_signature() const {
249 return has_tethering_signature_;
250}
251
Chris Masone092df3e2011-08-22 09:41:39 -0700252// static
mukesh agrawalb20776f2012-02-10 16:00:36 -0800253WiFiEndpoint *WiFiEndpoint::MakeOpenEndpoint(ProxyFactory *proxy_factory,
254 const WiFiRefPtr &wifi,
255 const string &ssid,
mukesh agrawale1d90e92012-02-15 17:36:08 -0800256 const string &bssid,
Paul Stewart3c504012013-01-17 17:49:58 -0800257 const string &network_mode,
mukesh agrawale1d90e92012-02-15 17:36:08 -0800258 uint16 frequency,
259 int16 signal_dbm) {
mukesh agrawal43970a22013-02-15 16:00:07 -0800260 return MakeEndpoint(proxy_factory, wifi, ssid, bssid, network_mode,
261 frequency, signal_dbm, false, false);
262}
263
Paul Stewartc67f0bd2013-12-06 12:14:50 -0800264
mukesh agrawal43970a22013-02-15 16:00:07 -0800265// static
266WiFiEndpoint *WiFiEndpoint::MakeEndpoint(ProxyFactory *proxy_factory,
267 const WiFiRefPtr &wifi,
268 const string &ssid,
269 const string &bssid,
270 const string &network_mode,
271 uint16 frequency,
272 int16 signal_dbm,
273 bool has_wpa_property,
274 bool has_rsn_property) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000275 map <string, ::DBus::Variant> args;
276 ::DBus::MessageIter writer;
277
Paul Stewart0654ece2013-03-26 15:21:26 -0700278 writer = args[WPASupplicant::kBSSPropertySSID].writer();
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000279 writer << vector<uint8_t>(ssid.begin(), ssid.end());
280
Paul Stewartc67f0bd2013-12-06 12:14:50 -0800281 vector<uint8_t> bssid_bytes = MakeHardwareAddressFromString(bssid);
Paul Stewart0654ece2013-03-26 15:21:26 -0700282 writer = args[WPASupplicant::kBSSPropertyBSSID].writer();
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000283 writer << bssid_bytes;
284
Paul Stewart0654ece2013-03-26 15:21:26 -0700285 args[WPASupplicant::kBSSPropertySignal].writer().append_int16(signal_dbm);
286 args[WPASupplicant::kBSSPropertyFrequency].writer().append_uint16(frequency);
287 args[WPASupplicant::kBSSPropertyMode].writer().append_string(
Paul Stewart3c504012013-01-17 17:49:58 -0800288 network_mode.c_str());
mukesh agrawal43970a22013-02-15 16:00:07 -0800289
290 if (has_wpa_property) {
291 ::DBus::MessageIter writer; // local is required; see HACKING
292 map <string, string> empty_dict;
Paul Stewart0654ece2013-03-26 15:21:26 -0700293 writer = args[WPASupplicant::kPropertyWPA].writer();
mukesh agrawal43970a22013-02-15 16:00:07 -0800294 writer << empty_dict;
295 }
296 if (has_rsn_property) {
297 ::DBus::MessageIter writer; // local is required; see HACKING
298 map <string, string> empty_dict;
Paul Stewart0654ece2013-03-26 15:21:26 -0700299 writer = args[WPASupplicant::kPropertyRSN].writer();
mukesh agrawal43970a22013-02-15 16:00:07 -0800300 writer << empty_dict;
301 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000302
mukesh agrawalb20776f2012-02-10 16:00:36 -0800303 return new WiFiEndpoint(
304 proxy_factory, wifi, bssid, args); // |bssid| fakes an RPC ID
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000305}
306
307// static
mukesh agrawal6e277772011-09-29 15:04:23 -0700308const char *WiFiEndpoint::ParseMode(const string &mode_string) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700309 if (mode_string == WPASupplicant::kNetworkModeInfrastructure) {
Ben Chanf024ef42013-09-20 14:21:38 -0700310 return kModeManaged;
Paul Stewart0654ece2013-03-26 15:21:26 -0700311 } else if (mode_string == WPASupplicant::kNetworkModeAdHoc) {
Ben Chanf024ef42013-09-20 14:21:38 -0700312 return kModeAdhoc;
Paul Stewart0654ece2013-03-26 15:21:26 -0700313 } else if (mode_string == WPASupplicant::kNetworkModeAccessPoint) {
Chris Masone092df3e2011-08-22 09:41:39 -0700314 NOTREACHED() << "Shill does not support AP mode at this time.";
315 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700316 } else {
Chris Masone092df3e2011-08-22 09:41:39 -0700317 NOTREACHED() << "Unknown WiFi endpoint mode!";
318 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700319 }
320}
321
mukesh agrawal6e277772011-09-29 15:04:23 -0700322// static
323const char *WiFiEndpoint::ParseSecurity(
Paul Stewartaffc0552013-03-25 07:50:15 -0700324 const map<string, ::DBus::Variant> &properties, SecurityFlags *flags) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700325 if (ContainsKey(properties, WPASupplicant::kPropertyRSN)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700326 // TODO(quiche): check type before casting
327 const map<string, ::DBus::Variant> rsn_properties(
Paul Stewart0654ece2013-03-26 15:21:26 -0700328 properties.find(WPASupplicant::kPropertyRSN)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700329 operator map<string, ::DBus::Variant>());
Paul Stewartaffc0552013-03-25 07:50:15 -0700330 set<KeyManagement> key_management;
331 ParseKeyManagementMethods(rsn_properties, &key_management);
332 flags->rsn_8021x = ContainsKey(key_management, kKeyManagement802_1x);
333 flags->rsn_psk = ContainsKey(key_management, kKeyManagementPSK);
mukesh agrawal6e277772011-09-29 15:04:23 -0700334 }
335
Paul Stewart0654ece2013-03-26 15:21:26 -0700336 if (ContainsKey(properties, WPASupplicant::kPropertyWPA)) {
mukesh agrawal165e6142011-11-22 02:22:56 +0000337 // TODO(quiche): check type before casting
mukesh agrawal6e277772011-09-29 15:04:23 -0700338 const map<string, ::DBus::Variant> rsn_properties(
Paul Stewart0654ece2013-03-26 15:21:26 -0700339 properties.find(WPASupplicant::kPropertyWPA)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700340 operator map<string, ::DBus::Variant>());
Paul Stewartaffc0552013-03-25 07:50:15 -0700341 set<KeyManagement> key_management;
342 ParseKeyManagementMethods(rsn_properties, &key_management);
343 flags->wpa_8021x = ContainsKey(key_management, kKeyManagement802_1x);
344 flags->wpa_psk = ContainsKey(key_management, kKeyManagementPSK);
mukesh agrawal6e277772011-09-29 15:04:23 -0700345 }
346
Paul Stewart0654ece2013-03-26 15:21:26 -0700347 if (ContainsKey(properties, WPASupplicant::kPropertyPrivacy)) {
Paul Stewartaffc0552013-03-25 07:50:15 -0700348 flags->privacy = properties.find(WPASupplicant::kPropertyPrivacy)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700349 reader().get_bool();
350 }
351
Paul Stewartaffc0552013-03-25 07:50:15 -0700352 if (flags->rsn_8021x || flags->wpa_8021x) {
Ben Chanf024ef42013-09-20 14:21:38 -0700353 return kSecurity8021x;
Paul Stewartaffc0552013-03-25 07:50:15 -0700354 } else if (flags->rsn_psk) {
Ben Chanf024ef42013-09-20 14:21:38 -0700355 return kSecurityRsn;
Paul Stewartaffc0552013-03-25 07:50:15 -0700356 } else if (flags->wpa_psk) {
Ben Chanf024ef42013-09-20 14:21:38 -0700357 return kSecurityWpa;
Paul Stewartaffc0552013-03-25 07:50:15 -0700358 } else if (flags->privacy) {
Ben Chanf024ef42013-09-20 14:21:38 -0700359 return kSecurityWep;
mukesh agrawal6e277772011-09-29 15:04:23 -0700360 } else {
Ben Chanf024ef42013-09-20 14:21:38 -0700361 return kSecurityNone;
mukesh agrawal6e277772011-09-29 15:04:23 -0700362 }
363}
364
365// static
366void WiFiEndpoint::ParseKeyManagementMethods(
367 const map<string, ::DBus::Variant> &security_method_properties,
368 set<KeyManagement> *key_management_methods) {
369 if (!ContainsKey(security_method_properties,
Paul Stewart0654ece2013-03-26 15:21:26 -0700370 WPASupplicant::kSecurityMethodPropertyKeyManagement)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700371 return;
372 }
373
374 // TODO(quiche): check type before cast
375 const vector<string> key_management_vec =
376 security_method_properties.
Paul Stewart0654ece2013-03-26 15:21:26 -0700377 find(WPASupplicant::kSecurityMethodPropertyKeyManagement)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700378 operator vector<string>();
379 for (vector<string>::const_iterator it = key_management_vec.begin();
380 it != key_management_vec.end();
381 ++it) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700382 if (EndsWith(*it, WPASupplicant::kKeyManagementMethodSuffixEAP, true)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700383 key_management_methods->insert(kKeyManagement802_1x);
384 } else if (
Paul Stewart0654ece2013-03-26 15:21:26 -0700385 EndsWith(*it, WPASupplicant::kKeyManagementMethodSuffixPSK, true)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700386 key_management_methods->insert(kKeyManagementPSK);
387 }
388 }
389}
390
Thieu Le1df7f4e2012-02-10 15:21:45 -0800391// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700392Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyModeFromFrequency(
Thieu Le1df7f4e2012-02-10 15:21:45 -0800393 const map<string, ::DBus::Variant> &properties, uint16 frequency) {
394 uint32_t max_rate = 0;
395 map<string, ::DBus::Variant>::const_iterator it =
Paul Stewart0654ece2013-03-26 15:21:26 -0700396 properties.find(WPASupplicant::kBSSPropertyRates);
Thieu Le1df7f4e2012-02-10 15:21:45 -0800397 if (it != properties.end()) {
398 vector<uint32_t> rates = it->second.operator vector<uint32_t>();
399 if (rates.size() > 0)
400 max_rate = rates[0]; // Rates are sorted in descending order
401 }
402
403 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
Thieu Le1df7f4e2012-02-10 15:21:45 -0800404 if (frequency < 3000) {
405 // 2.4GHz legacy, check for tx rate for 11b-only
406 // (note 22M is valid)
407 if (max_rate < 24000000)
408 phy_mode = Metrics::kWiFiNetworkPhyMode11b;
409 else
410 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
411 } else {
412 phy_mode = Metrics::kWiFiNetworkPhyMode11a;
413 }
414
415 return phy_mode;
416}
417
418// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700419bool WiFiEndpoint::ParseIEs(
420 const map<string, ::DBus::Variant> &properties,
421 Metrics::WiFiNetworkPhyMode *phy_mode,
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800422 VendorInformation *vendor_information,
Paul Stewartbdbd3c32013-04-17 09:47:21 -0700423 bool *ieee80211w_required, string *country_code) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700424
425 map<string, ::DBus::Variant>::const_iterator ies_property =
Paul Stewart0654ece2013-03-26 15:21:26 -0700426 properties.find(WPASupplicant::kBSSPropertyIEs);
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700427 if (ies_property == properties.end()) {
428 SLOG(WiFi, 2) << __func__ << ": No IE property in BSS.";
429 return false;
Thieu Le1df7f4e2012-02-10 15:21:45 -0800430 }
431
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700432 vector<uint8_t> ies = ies_property->second.operator vector<uint8_t>();
433
434
435 // Format of an information element:
436 // 1 1 1 - 252
437 // +------+--------+----------------+
438 // | Type | Length | Data |
439 // +------+--------+----------------+
440 *phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
441 bool found_ht = false;
442 bool found_erp = false;
443 int ie_len = 0;
444 vector<uint8_t>::iterator it;
445 for (it = ies.begin();
446 std::distance(it, ies.end()) > 1; // Ensure Length field is within PDU.
447 it += ie_len) {
448 ie_len = 2 + *(it + 1);
449 if (std::distance(it, ies.end()) < ie_len) {
450 LOG(ERROR) << __func__ << ": IE extends past containing PDU.";
451 break;
452 }
453 switch (*it) {
Paul Stewartbdbd3c32013-04-17 09:47:21 -0700454 case IEEE_80211::kElemIdCountry:
455 // Retrieve 2-character country code from the beginning of the element.
456 if (ie_len >= 4) {
457 *country_code = string(it + 2, it + 4);
458 }
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700459 case IEEE_80211::kElemIdErp:
460 if (!found_ht) {
461 *phy_mode = Metrics::kWiFiNetworkPhyMode11g;
462 }
463 found_erp = true;
464 break;
465 case IEEE_80211::kElemIdHTCap:
466 case IEEE_80211::kElemIdHTInfo:
467 *phy_mode = Metrics::kWiFiNetworkPhyMode11n;
468 found_ht = true;
469 break;
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800470 case IEEE_80211::kElemIdRSN:
471 ParseWPACapabilities(it + 2, it + ie_len, ieee80211w_required);
472 break;
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700473 case IEEE_80211::kElemIdVendor:
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800474 ParseVendorIE(it + 2, it + ie_len, vendor_information,
475 ieee80211w_required);
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700476 break;
477 }
478 }
479 return found_ht || found_erp;
480}
481
482// static
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800483void WiFiEndpoint::ParseWPACapabilities(
484 vector<uint8_t>::const_iterator ie,
485 vector<uint8_t>::const_iterator end,
486 bool *ieee80211w_required) {
487 // Format of an RSN Information Element:
488 // 2 4
489 // +------+--------------------+
490 // | Type | Group Cipher Suite |
491 // +------+--------------------+
492 // 2 4 * pairwise count
493 // +-----------------------+---------------------+
494 // | Pairwise Cipher Count | Pairwise Ciphers... |
495 // +-----------------------+---------------------+
496 // 2 4 * authkey count
497 // +-----------------------+---------------------+
498 // | AuthKey Suite Count | AuthKey Suites... |
499 // +-----------------------+---------------------+
500 // 2
501 // +------------------+
502 // | RSN Capabilities |
503 // +------------------+
504 // 2 16 * pmkid count
505 // +------------------+-------------------+
506 // | PMKID Count | PMKIDs... |
507 // +------------------+-------------------+
508 // 4
509 // +-------------------------------+
510 // | Group Management Cipher Suite |
511 // +-------------------------------+
512 if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountOffset) {
513 return;
514 }
515 ie += IEEE_80211::kRSNIECipherCountOffset;
516
517 // Advance past the pairwise and authkey ciphers. Each is a little-endian
518 // cipher count followed by n * cipher_selector.
519 for (int i = 0; i < IEEE_80211::kRSNIENumCiphers; ++i) {
520 // Retrieve a little-endian cipher count.
521 if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountLen) {
522 return;
523 }
524 uint16 cipher_count = *ie | (*(ie + 1) << 8);
525
526 // Skip over the cipher selectors.
527 int skip_length = IEEE_80211::kRSNIECipherCountLen +
528 cipher_count * IEEE_80211::kRSNIESelectorLen;
529 if (std::distance(ie, end) < skip_length) {
530 return;
531 }
532 ie += skip_length;
533 }
534
535 if (std::distance(ie, end) < IEEE_80211::kRSNIECapabilitiesLen) {
536 return;
537 }
538
539 // Retrieve a little-endian capabilities bitfield.
540 uint16 capabilities = *ie | (*(ie + 1) << 8);
541
542 if (capabilities & IEEE_80211::kRSNCapabilityFrameProtectionRequired &&
543 ieee80211w_required) {
544 // Never set this value to false, since there may be multiple RSN
545 // information elements.
546 *ieee80211w_required = true;
547 }
548}
549
550
551// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700552void WiFiEndpoint::ParseVendorIE(vector<uint8_t>::const_iterator ie,
553 vector<uint8_t>::const_iterator end,
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800554 VendorInformation *vendor_information,
555 bool *ieee80211w_required) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700556 // Format of an vendor-specific information element (with type
557 // and length field for the IE removed by the caller):
558 // 3 1 1 - 248
559 // +------------+----------+----------------+
560 // | OUI | OUI Type | Data |
561 // +------------+----------+----------------+
562
563 if (std::distance(ie, end) < 4) {
564 LOG(ERROR) << __func__ << ": no room in IE for OUI and type field.";
565 return;
566 }
567 uint32_t oui = (*ie << 16) | (*(ie + 1) << 8) | *(ie + 2);
568 uint8_t oui_type = *(ie + 3);
569 ie += 4;
570
571 if (oui == IEEE_80211::kOUIVendorMicrosoft &&
572 oui_type == IEEE_80211::kOUIMicrosoftWPS) {
573 // Format of a WPS data element:
574 // 2 2
575 // +------+--------+----------------+
576 // | Type | Length | Data |
577 // +------+--------+----------------+
578 while (std::distance(ie, end) >= 4) {
579 int element_type = (*ie << 8) | *(ie + 1);
580 int element_length = (*(ie + 2) << 8) | *(ie + 3);
581 ie += 4;
582 if (std::distance(ie, end) < element_length) {
583 LOG(ERROR) << __func__ << ": WPS element extends past containing PDU.";
584 break;
585 }
586 string s(ie, ie + element_length);
587 if (IsStringASCII(s)) {
588 switch (element_type) {
589 case IEEE_80211::kWPSElementManufacturer:
590 vendor_information->wps_manufacturer = s;
591 break;
592 case IEEE_80211::kWPSElementModelName:
593 vendor_information->wps_model_name = s;
594 break;
595 case IEEE_80211::kWPSElementModelNumber:
596 vendor_information->wps_model_number = s;
597 break;
598 case IEEE_80211::kWPSElementDeviceName:
599 vendor_information->wps_device_name = s;
600 break;
601 }
602 }
603 ie += element_length;
604 }
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800605 } else if (oui == IEEE_80211::kOUIVendorMicrosoft &&
606 oui_type == IEEE_80211::kOUIMicrosoftWPA) {
607 ParseWPACapabilities(ie, end, ieee80211w_required);
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700608 } else if (oui != IEEE_80211::kOUIVendorEpigram &&
609 oui != IEEE_80211::kOUIVendorMicrosoft) {
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800610 vendor_information->oui_set.insert(oui);
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700611 }
Thieu Le1df7f4e2012-02-10 15:21:45 -0800612}
613
Paul Stewartfa11e282013-12-02 22:04:25 -0800614void WiFiEndpoint::CheckForTetheringSignature() {
615 has_tethering_signature_ =
616 Tethering::IsAndroidBSSID(bssid_) ||
617 (Tethering::IsLocallyAdministeredBSSID(bssid_) &&
618 Tethering::HasIosOui(vendor_information_.oui_set));
619}
620
Paul Stewartc67f0bd2013-12-06 12:14:50 -0800621// static
622vector<uint8_t> WiFiEndpoint::MakeHardwareAddressFromString(
623 const string &bssid_string) {
624 string bssid_nosep;
625 RemoveChars(bssid_string, ":", &bssid_nosep);
626 vector<uint8_t> bssid_bytes;
627 base::HexStringToBytes(bssid_nosep, &bssid_bytes);
628 if (bssid_bytes.size() != kBSSIDLength) {
629 return vector<uint8_t>();
630 }
631 return bssid_bytes;
632}
633
634// static
635string WiFiEndpoint::MakeStringFromHardwareAddress(
636 const vector<uint8_t> &bssid) {
637 CHECK_EQ(kBSSIDLength, bssid.size());
638 return StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
639 bssid[0], bssid[1], bssid[2],
640 bssid[3], bssid[4], bssid[5]);
641}
642
mukesh agrawalb54601c2011-06-07 17:39:22 -0700643} // namespace shill