blob: 5491fa9df4ff45734ab3caae8d6b63f4bc1bf5af [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
Ben Chand6a8b512014-11-18 10:45:15 -08005#include "shill/wifi/wifi_endpoint.h"
Chris Masone092df3e2011-08-22 09:41:39 -07006
Paul Stewart72b2fdc2012-06-02 08:58:51 -07007#include <algorithm>
8
Eric Shienbrood3e20a232012-02-16 11:35:56 -05009#include <base/stl_util.h>
Ben Chana0ddf462014-02-06 11:32:42 -080010#include <base/strings/stringprintf.h>
11#include <base/strings/string_number_conversions.h>
12#include <base/strings/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
Christopher Wileyb691efd2012-08-09 13:51:51 -070015#include "shill/logging.h"
mukesh agrawalf6b32092013-04-10 15:49:55 -070016#include "shill/metrics.h"
Peter Qiu02e3dc32014-10-31 10:15:00 -070017#include "shill/net/ieee80211.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080018#include "shill/proxy_factory.h"
Ben Chanda69ecf2014-11-19 07:44:42 -080019#include "shill/supplicant/supplicant_bss_proxy_interface.h"
20#include "shill/supplicant/wpa_supplicant.h"
Paul Stewartfa11e282013-12-02 22:04:25 -080021#include "shill/tethering.h"
Ben Chand6a8b512014-11-18 10:45:15 -080022#include "shill/wifi/wifi.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070023
Ben Chana0ddf462014-02-06 11:32:42 -080024using base::StringPrintf;
mukesh agrawal6e277772011-09-29 15:04:23 -070025using 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
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070032namespace Logging {
33static auto kModuleLogScope = ScopeLogger::kWiFi;
34static string ObjectID(WiFiEndpoint *w) { return "(wifi_endpoint)"; }
35}
36
mukesh agrawalb20776f2012-02-10 16:00:36 -080037WiFiEndpoint::WiFiEndpoint(ProxyFactory *proxy_factory,
38 const WiFiRefPtr &device,
39 const string &rpc_id,
40 const map<string, ::DBus::Variant> &properties)
41 : frequency_(0),
mukesh agrawalf6b32092013-04-10 15:49:55 -070042 physical_mode_(Metrics::kWiFiNetworkPhyModeUndef),
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080043 ieee80211w_required_(false),
mukesh agrawalb20776f2012-02-10 16:00:36 -080044 proxy_factory_(proxy_factory),
45 device_(device),
46 rpc_id_(rpc_id) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070047 // XXX will segfault on missing properties
48 ssid_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070049 properties.find(WPASupplicant::kBSSPropertySSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070050 operator std::vector<uint8_t>();
51 bssid_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070052 properties.find(WPASupplicant::kBSSPropertyBSSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070053 operator std::vector<uint8_t>();
54 signal_strength_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070055 properties.find(WPASupplicant::kBSSPropertySignal)->second.
mukesh agrawal15908392011-11-16 18:29:25 +000056 reader().get_int16();
Thieu Lee41a72d2012-02-06 20:46:51 +000057 map<string, ::DBus::Variant>::const_iterator it =
Paul Stewart0654ece2013-03-26 15:21:26 -070058 properties.find(WPASupplicant::kBSSPropertyFrequency);
Thieu Lee41a72d2012-02-06 20:46:51 +000059 if (it != properties.end())
60 frequency_ = it->second.reader().get_uint16();
Paul Stewart72b2fdc2012-06-02 08:58:51 -070061
62 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080063 if (!ParseIEs(properties, &phy_mode, &vendor_information_,
Paul Stewartbdbd3c32013-04-17 09:47:21 -070064 &ieee80211w_required_, &country_code_)) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -070065 phy_mode = DeterminePhyModeFromFrequency(properties, frequency_);
66 }
67 physical_mode_ = phy_mode;
68
Chris Masone092df3e2011-08-22 09:41:39 -070069 network_mode_ = ParseMode(
Paul Stewart0654ece2013-03-26 15:21:26 -070070 properties.find(WPASupplicant::kBSSPropertyMode)->second);
Paul Stewartaffc0552013-03-25 07:50:15 -070071 set_security_mode(ParseSecurity(properties, &security_flags_));
Paul Stewart0654ece2013-03-26 15:21:26 -070072 has_rsn_property_ = ContainsKey(properties, WPASupplicant::kPropertyRSN);
73 has_wpa_property_ = ContainsKey(properties, WPASupplicant::kPropertyWPA);
mukesh agrawalb54601c2011-06-07 17:39:22 -070074
Chris Masone092df3e2011-08-22 09:41:39 -070075 if (network_mode_.empty()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070076 // XXX log error?
77 }
78
79 ssid_string_ = string(ssid_.begin(), ssid_.end());
mukesh agrawal16bc1b82012-02-09 18:38:26 -080080 WiFi::SanitizeSSID(&ssid_string_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070081 ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size());
Peter Qiu62abf312015-05-05 12:58:05 -070082 bssid_string_ = Device::MakeStringFromHardwareAddress(bssid_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070083 bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size());
Paul Stewartfa11e282013-12-02 22:04:25 -080084
85 CheckForTetheringSignature();
mukesh agrawalb54601c2011-06-07 17:39:22 -070086}
87
88WiFiEndpoint::~WiFiEndpoint() {}
89
mukesh agrawalb20776f2012-02-10 16:00:36 -080090void WiFiEndpoint::Start() {
91 supplicant_bss_proxy_.reset(
92 proxy_factory_->CreateSupplicantBSSProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -070093 this, rpc_id_, WPASupplicant::kDBusAddr));
mukesh agrawalb20776f2012-02-10 16:00:36 -080094}
95
96void WiFiEndpoint::PropertiesChanged(
97 const map<string, ::DBus::Variant> &properties) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070098 SLOG(this, 2) << __func__;
Paul Stewartaffc0552013-03-25 07:50:15 -070099 bool should_notify = false;
mukesh agrawalb20776f2012-02-10 16:00:36 -0800100 map<string, ::DBus::Variant>::const_iterator properties_it =
Paul Stewart0654ece2013-03-26 15:21:26 -0700101 properties.find(WPASupplicant::kBSSPropertySignal);
mukesh agrawalb20776f2012-02-10 16:00:36 -0800102 if (properties_it != properties.end()) {
103 signal_strength_ = properties_it->second.reader().get_int16();
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700104 SLOG(this, 2) << "WiFiEndpoint " << bssid_string_ << " signal is now "
Ben Chanfad4a0b2012-04-18 15:49:59 -0700105 << signal_strength_;
Paul Stewartaffc0552013-03-25 07:50:15 -0700106 should_notify = true;
107 }
108
109 properties_it = properties.find(WPASupplicant::kBSSPropertyMode);
110 if (properties_it != properties.end()) {
111 string new_mode = ParseMode(properties_it->second);
112 if (new_mode != network_mode_) {
113 network_mode_ = new_mode;
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700114 SLOG(this, 2) << "WiFiEndpoint " << bssid_string_ << " mode is now "
Paul Stewartaffc0552013-03-25 07:50:15 -0700115 << network_mode_;
116 should_notify = true;
117 }
118 }
119
120 const char *new_security_mode = ParseSecurity(properties, &security_flags_);
121 if (new_security_mode != security_mode()) {
122 set_security_mode(new_security_mode);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700123 SLOG(this, 2) << "WiFiEndpoint " << bssid_string_ << " security is now "
Paul Stewartaffc0552013-03-25 07:50:15 -0700124 << security_mode();
125 should_notify = true;
126 }
127
128 if (should_notify) {
Paul Stewart3c504012013-01-17 17:49:58 -0800129 device_->NotifyEndpointChanged(this);
mukesh agrawalb20776f2012-02-10 16:00:36 -0800130 }
131}
132
Ben Chan7fab8972014-08-10 17:14:46 -0700133void WiFiEndpoint::UpdateSignalStrength(int16_t strength) {
Alex Vakulenko8a532292014-06-16 17:18:44 -0700134 if (signal_strength_ == strength) {
Paul Stewart7cd45722013-08-12 14:50:14 -0700135 return;
136 }
137
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700138 SLOG(this, 2) << __func__ << ": signal strength "
Paul Stewart7cd45722013-08-12 14:50:14 -0700139 << signal_strength_ << " -> " << strength;
140 signal_strength_ = strength;
141 device_->NotifyEndpointChanged(this);
142}
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700143
144map<string, string> WiFiEndpoint::GetVendorInformation() const {
145 map<string, string> vendor_information;
146 if (!vendor_information_.wps_manufacturer.empty()) {
147 vendor_information[kVendorWPSManufacturerProperty] =
148 vendor_information_.wps_manufacturer;
149 }
150 if (!vendor_information_.wps_model_name.empty()) {
151 vendor_information[kVendorWPSModelNameProperty] =
152 vendor_information_.wps_model_name;
153 }
154 if (!vendor_information_.wps_model_number.empty()) {
155 vendor_information[kVendorWPSModelNumberProperty] =
156 vendor_information_.wps_model_number;
157 }
158 if (!vendor_information_.wps_device_name.empty()) {
159 vendor_information[kVendorWPSDeviceNameProperty] =
160 vendor_information_.wps_device_name;
161 }
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800162 if (!vendor_information_.oui_set.empty()) {
163 vector<string> oui_vector;
Paul Stewart6db7b242014-05-02 15:34:21 -0700164 for (auto oui : vendor_information_.oui_set) {
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800165 oui_vector.push_back(
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700166 StringPrintf("%02x-%02x-%02x",
Paul Stewart6db7b242014-05-02 15:34:21 -0700167 oui >> 16, (oui >> 8) & 0xff, oui & 0xff));
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700168 }
169 vendor_information[kVendorOUIListProperty] =
Paul Stewarte2c1b9f2013-12-03 19:55:46 -0800170 JoinString(oui_vector, ' ');
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700171 }
172 return vendor_information;
173}
174
Chris Masone092df3e2011-08-22 09:41:39 -0700175// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700176uint32_t WiFiEndpoint::ModeStringToUint(const string &mode_string) {
Ben Chanf024ef42013-09-20 14:21:38 -0700177 if (mode_string == kModeManaged)
Paul Stewart0654ece2013-03-26 15:21:26 -0700178 return WPASupplicant::kNetworkModeInfrastructureInt;
Ben Chanf024ef42013-09-20 14:21:38 -0700179 else if (mode_string == kModeAdhoc)
Paul Stewart0654ece2013-03-26 15:21:26 -0700180 return WPASupplicant::kNetworkModeAdHocInt;
Chris Masone092df3e2011-08-22 09:41:39 -0700181 else
182 NOTIMPLEMENTED() << "Shill dos not support " << mode_string
183 << " mode at this time.";
184 return 0;
185}
186
mukesh agrawal6e277772011-09-29 15:04:23 -0700187const vector<uint8_t> &WiFiEndpoint::ssid() const {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700188 return ssid_;
189}
190
191const string &WiFiEndpoint::ssid_string() const {
192 return ssid_string_;
193}
194
195const string &WiFiEndpoint::ssid_hex() const {
196 return ssid_hex_;
197}
198
199const string &WiFiEndpoint::bssid_string() const {
200 return bssid_string_;
201}
202
203const string &WiFiEndpoint::bssid_hex() const {
204 return bssid_hex_;
205}
206
Paul Stewartbdbd3c32013-04-17 09:47:21 -0700207const string &WiFiEndpoint::country_code() const {
208 return country_code_;
209}
210
Paul Stewart3c504012013-01-17 17:49:58 -0800211const WiFiRefPtr &WiFiEndpoint::device() const {
212 return device_;
213}
214
mukesh agrawalb54601c2011-06-07 17:39:22 -0700215int16_t WiFiEndpoint::signal_strength() const {
216 return signal_strength_;
217}
218
Ben Chan7fab8972014-08-10 17:14:46 -0700219uint16_t WiFiEndpoint::frequency() const {
Thieu Lee41a72d2012-02-06 20:46:51 +0000220 return frequency_;
221}
222
Ben Chan7fab8972014-08-10 17:14:46 -0700223uint16_t WiFiEndpoint::physical_mode() const {
Thieu Le1df7f4e2012-02-10 15:21:45 -0800224 return physical_mode_;
225}
226
Chris Masone092df3e2011-08-22 09:41:39 -0700227const string &WiFiEndpoint::network_mode() const {
mukesh agrawal6e277772011-09-29 15:04:23 -0700228 return network_mode_;
229}
230
231const string &WiFiEndpoint::security_mode() const {
232 return security_mode_;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700233}
234
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800235bool WiFiEndpoint::ieee80211w_required() const {
236 return ieee80211w_required_;
237}
238
mukesh agrawal43970a22013-02-15 16:00:07 -0800239bool WiFiEndpoint::has_rsn_property() const {
240 return has_rsn_property_;
241}
242
243bool WiFiEndpoint::has_wpa_property() const {
244 return has_wpa_property_;
245}
246
Paul Stewartfa11e282013-12-02 22:04:25 -0800247bool WiFiEndpoint::has_tethering_signature() const {
248 return has_tethering_signature_;
249}
250
Chris Masone092df3e2011-08-22 09:41:39 -0700251// static
mukesh agrawalb20776f2012-02-10 16:00:36 -0800252WiFiEndpoint *WiFiEndpoint::MakeOpenEndpoint(ProxyFactory *proxy_factory,
253 const WiFiRefPtr &wifi,
254 const string &ssid,
mukesh agrawale1d90e92012-02-15 17:36:08 -0800255 const string &bssid,
Paul Stewart3c504012013-01-17 17:49:58 -0800256 const string &network_mode,
Ben Chan7fab8972014-08-10 17:14:46 -0700257 uint16_t frequency,
258 int16_t signal_dbm) {
mukesh agrawal43970a22013-02-15 16:00:07 -0800259 return MakeEndpoint(proxy_factory, wifi, ssid, bssid, network_mode,
260 frequency, signal_dbm, false, false);
261}
262
Paul Stewartc67f0bd2013-12-06 12:14:50 -0800263
mukesh agrawal43970a22013-02-15 16:00:07 -0800264// static
265WiFiEndpoint *WiFiEndpoint::MakeEndpoint(ProxyFactory *proxy_factory,
266 const WiFiRefPtr &wifi,
267 const string &ssid,
268 const string &bssid,
269 const string &network_mode,
Ben Chan7fab8972014-08-10 17:14:46 -0700270 uint16_t frequency,
271 int16_t signal_dbm,
mukesh agrawal43970a22013-02-15 16:00:07 -0800272 bool has_wpa_property,
273 bool has_rsn_property) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000274 map <string, ::DBus::Variant> args;
275 ::DBus::MessageIter writer;
276
Paul Stewart0654ece2013-03-26 15:21:26 -0700277 writer = args[WPASupplicant::kBSSPropertySSID].writer();
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000278 writer << vector<uint8_t>(ssid.begin(), ssid.end());
279
Peter Qiu62abf312015-05-05 12:58:05 -0700280 vector<uint8_t> bssid_bytes =
281 Device::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(
Alex Vakulenko8a532292014-06-16 17:18:44 -0700304 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.";
Ben Chan0afd90f2014-09-30 13:34:45 -0700315 return nullptr;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700316 } else {
Chris Masone092df3e2011-08-22 09:41:39 -0700317 NOTREACHED() << "Unknown WiFi endpoint mode!";
Ben Chan0afd90f2014-09-30 13:34:45 -0700318 return nullptr;
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>();
Paul Stewart6db7b242014-05-02 15:34:21 -0700379 for (const auto &method : key_management_vec) {
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700380 if (base::EndsWith(method, WPASupplicant::kKeyManagementMethodSuffixEAP,
381 true)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700382 key_management_methods->insert(kKeyManagement802_1x);
Alex Vakulenkoccab3f92015-06-15 12:53:22 -0700383 } else if (base::EndsWith(method,
384 WPASupplicant::kKeyManagementMethodSuffixPSK,
385 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(
Ben Chan7fab8972014-08-10 17:14:46 -0700393 const map<string, ::DBus::Variant> &properties, uint16_t frequency) {
Thieu Le1df7f4e2012-02-10 15:21:45 -0800394 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()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700428 SLOG(nullptr, 2) << __func__ << ": No IE property in BSS.";
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700429 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 }
Ben Chan7fab8972014-08-10 17:14:46 -0700524 uint16_t cipher_count = *ie | (*(ie + 1) << 8);
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800525
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.
Ben Chan7fab8972014-08-10 17:14:46 -0700540 uint16_t capabilities = *ie | (*(ie + 1) << 8);
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800541
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);
Ben Chan6fbf64f2014-05-21 18:07:01 -0700587 if (base::IsStringASCII(s)) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700588 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
mukesh agrawalb54601c2011-06-07 17:39:22 -0700621} // namespace shill