blob: f97a65b84fa1a2b89aa2f141b9e6883c398c8f58 [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"
mukesh agrawal16bc1b82012-02-09 18:38:26 -080020#include "shill/wifi.h"
mukesh agrawalb20776f2012-02-10 16:00:36 -080021#include "shill/wifi_endpoint.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070022#include "shill/wpa_supplicant.h"
23
24using std::map;
25using std::set;
mukesh agrawalb54601c2011-06-07 17:39:22 -070026using std::string;
mukesh agrawal6e277772011-09-29 15:04:23 -070027using std::vector;
mukesh agrawalb54601c2011-06-07 17:39:22 -070028
29namespace shill {
30
mukesh agrawalb20776f2012-02-10 16:00:36 -080031WiFiEndpoint::WiFiEndpoint(ProxyFactory *proxy_factory,
32 const WiFiRefPtr &device,
33 const string &rpc_id,
34 const map<string, ::DBus::Variant> &properties)
35 : frequency_(0),
mukesh agrawalf6b32092013-04-10 15:49:55 -070036 physical_mode_(Metrics::kWiFiNetworkPhyModeUndef),
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080037 ieee80211w_required_(false),
mukesh agrawalb20776f2012-02-10 16:00:36 -080038 proxy_factory_(proxy_factory),
39 device_(device),
40 rpc_id_(rpc_id) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070041 // XXX will segfault on missing properties
42 ssid_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070043 properties.find(WPASupplicant::kBSSPropertySSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070044 operator std::vector<uint8_t>();
45 bssid_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070046 properties.find(WPASupplicant::kBSSPropertyBSSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070047 operator std::vector<uint8_t>();
48 signal_strength_ =
Paul Stewart0654ece2013-03-26 15:21:26 -070049 properties.find(WPASupplicant::kBSSPropertySignal)->second.
mukesh agrawal15908392011-11-16 18:29:25 +000050 reader().get_int16();
Thieu Lee41a72d2012-02-06 20:46:51 +000051 map<string, ::DBus::Variant>::const_iterator it =
Paul Stewart0654ece2013-03-26 15:21:26 -070052 properties.find(WPASupplicant::kBSSPropertyFrequency);
Thieu Lee41a72d2012-02-06 20:46:51 +000053 if (it != properties.end())
54 frequency_ = it->second.reader().get_uint16();
Paul Stewart72b2fdc2012-06-02 08:58:51 -070055
56 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
Paul Stewarta5e7d5f2013-01-09 18:06:15 -080057 if (!ParseIEs(properties, &phy_mode, &vendor_information_,
Paul Stewartbdbd3c32013-04-17 09:47:21 -070058 &ieee80211w_required_, &country_code_)) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -070059 phy_mode = DeterminePhyModeFromFrequency(properties, frequency_);
60 }
61 physical_mode_ = phy_mode;
62
Chris Masone092df3e2011-08-22 09:41:39 -070063 network_mode_ = ParseMode(
Paul Stewart0654ece2013-03-26 15:21:26 -070064 properties.find(WPASupplicant::kBSSPropertyMode)->second);
Paul Stewartaffc0552013-03-25 07:50:15 -070065 set_security_mode(ParseSecurity(properties, &security_flags_));
Paul Stewart0654ece2013-03-26 15:21:26 -070066 has_rsn_property_ = ContainsKey(properties, WPASupplicant::kPropertyRSN);
67 has_wpa_property_ = ContainsKey(properties, WPASupplicant::kPropertyWPA);
mukesh agrawalb54601c2011-06-07 17:39:22 -070068
Chris Masone092df3e2011-08-22 09:41:39 -070069 if (network_mode_.empty()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070070 // XXX log error?
71 }
72
73 ssid_string_ = string(ssid_.begin(), ssid_.end());
mukesh agrawal16bc1b82012-02-09 18:38:26 -080074 WiFi::SanitizeSSID(&ssid_string_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070075 ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size());
76 bssid_string_ = StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
77 bssid_[0], bssid_[1], bssid_[2],
78 bssid_[3], bssid_[4], bssid_[5]);
79 bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size());
80}
81
82WiFiEndpoint::~WiFiEndpoint() {}
83
mukesh agrawalb20776f2012-02-10 16:00:36 -080084void WiFiEndpoint::Start() {
85 supplicant_bss_proxy_.reset(
86 proxy_factory_->CreateSupplicantBSSProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -070087 this, rpc_id_, WPASupplicant::kDBusAddr));
mukesh agrawalb20776f2012-02-10 16:00:36 -080088}
89
90void WiFiEndpoint::PropertiesChanged(
91 const map<string, ::DBus::Variant> &properties) {
Darin Petkov3abc3be2012-06-27 10:48:23 +020092 SLOG(WiFi, 2) << __func__;
Paul Stewartaffc0552013-03-25 07:50:15 -070093 bool should_notify = false;
mukesh agrawalb20776f2012-02-10 16:00:36 -080094 map<string, ::DBus::Variant>::const_iterator properties_it =
Paul Stewart0654ece2013-03-26 15:21:26 -070095 properties.find(WPASupplicant::kBSSPropertySignal);
mukesh agrawalb20776f2012-02-10 16:00:36 -080096 if (properties_it != properties.end()) {
97 signal_strength_ = properties_it->second.reader().get_int16();
Ben Chanfad4a0b2012-04-18 15:49:59 -070098 SLOG(WiFi, 2) << "WiFiEndpoint " << bssid_string_ << " signal is now "
99 << signal_strength_;
Paul Stewartaffc0552013-03-25 07:50:15 -0700100 should_notify = true;
101 }
102
103 properties_it = properties.find(WPASupplicant::kBSSPropertyMode);
104 if (properties_it != properties.end()) {
105 string new_mode = ParseMode(properties_it->second);
106 if (new_mode != network_mode_) {
107 network_mode_ = new_mode;
108 SLOG(WiFi, 2) << "WiFiEndpoint " << bssid_string_ << " mode is now "
109 << network_mode_;
110 should_notify = true;
111 }
112 }
113
114 const char *new_security_mode = ParseSecurity(properties, &security_flags_);
115 if (new_security_mode != security_mode()) {
116 set_security_mode(new_security_mode);
117 SLOG(WiFi, 2) << "WiFiEndpoint " << bssid_string_ << " security is now "
118 << security_mode();
119 should_notify = true;
120 }
121
122 if (should_notify) {
Paul Stewart3c504012013-01-17 17:49:58 -0800123 device_->NotifyEndpointChanged(this);
mukesh agrawalb20776f2012-02-10 16:00:36 -0800124 }
125}
126
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700127
128map<string, string> WiFiEndpoint::GetVendorInformation() const {
129 map<string, string> vendor_information;
130 if (!vendor_information_.wps_manufacturer.empty()) {
131 vendor_information[kVendorWPSManufacturerProperty] =
132 vendor_information_.wps_manufacturer;
133 }
134 if (!vendor_information_.wps_model_name.empty()) {
135 vendor_information[kVendorWPSModelNameProperty] =
136 vendor_information_.wps_model_name;
137 }
138 if (!vendor_information_.wps_model_number.empty()) {
139 vendor_information[kVendorWPSModelNumberProperty] =
140 vendor_information_.wps_model_number;
141 }
142 if (!vendor_information_.wps_device_name.empty()) {
143 vendor_information[kVendorWPSDeviceNameProperty] =
144 vendor_information_.wps_device_name;
145 }
146 if (!vendor_information_.oui_list.empty()) {
147 vector<string> oui_list;
148 set<uint32_t>::const_iterator it;
149 for (it = vendor_information_.oui_list.begin();
150 it != vendor_information_.oui_list.end();
151 ++it) {
152 oui_list.push_back(
153 StringPrintf("%02x-%02x-%02x",
154 *it >> 16, (*it >> 8) & 0xff, *it & 0xff));
155 }
156 vendor_information[kVendorOUIListProperty] =
157 JoinString(oui_list, ' ');
158 }
159 return vendor_information;
160}
161
Chris Masone092df3e2011-08-22 09:41:39 -0700162// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700163uint32_t WiFiEndpoint::ModeStringToUint(const string &mode_string) {
Chris Masone092df3e2011-08-22 09:41:39 -0700164 if (mode_string == flimflam::kModeManaged)
Paul Stewart0654ece2013-03-26 15:21:26 -0700165 return WPASupplicant::kNetworkModeInfrastructureInt;
Chris Masone092df3e2011-08-22 09:41:39 -0700166 else if (mode_string == flimflam::kModeAdhoc)
Paul Stewart0654ece2013-03-26 15:21:26 -0700167 return WPASupplicant::kNetworkModeAdHocInt;
Chris Masone092df3e2011-08-22 09:41:39 -0700168 else
169 NOTIMPLEMENTED() << "Shill dos not support " << mode_string
170 << " mode at this time.";
171 return 0;
172}
173
mukesh agrawal6e277772011-09-29 15:04:23 -0700174const vector<uint8_t> &WiFiEndpoint::ssid() const {
mukesh agrawalb54601c2011-06-07 17:39:22 -0700175 return ssid_;
176}
177
178const string &WiFiEndpoint::ssid_string() const {
179 return ssid_string_;
180}
181
182const string &WiFiEndpoint::ssid_hex() const {
183 return ssid_hex_;
184}
185
186const string &WiFiEndpoint::bssid_string() const {
187 return bssid_string_;
188}
189
190const string &WiFiEndpoint::bssid_hex() const {
191 return bssid_hex_;
192}
193
Paul Stewartbdbd3c32013-04-17 09:47:21 -0700194const string &WiFiEndpoint::country_code() const {
195 return country_code_;
196}
197
Paul Stewart3c504012013-01-17 17:49:58 -0800198const WiFiRefPtr &WiFiEndpoint::device() const {
199 return device_;
200}
201
mukesh agrawalb54601c2011-06-07 17:39:22 -0700202int16_t WiFiEndpoint::signal_strength() const {
203 return signal_strength_;
204}
205
Thieu Lee41a72d2012-02-06 20:46:51 +0000206uint16 WiFiEndpoint::frequency() const {
207 return frequency_;
208}
209
Thieu Le1df7f4e2012-02-10 15:21:45 -0800210uint16 WiFiEndpoint::physical_mode() const {
211 return physical_mode_;
212}
213
Chris Masone092df3e2011-08-22 09:41:39 -0700214const string &WiFiEndpoint::network_mode() const {
mukesh agrawal6e277772011-09-29 15:04:23 -0700215 return network_mode_;
216}
217
218const string &WiFiEndpoint::security_mode() const {
219 return security_mode_;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700220}
221
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800222bool WiFiEndpoint::ieee80211w_required() const {
223 return ieee80211w_required_;
224}
225
mukesh agrawal43970a22013-02-15 16:00:07 -0800226bool WiFiEndpoint::has_rsn_property() const {
227 return has_rsn_property_;
228}
229
230bool WiFiEndpoint::has_wpa_property() const {
231 return has_wpa_property_;
232}
233
Chris Masone092df3e2011-08-22 09:41:39 -0700234// static
mukesh agrawalb20776f2012-02-10 16:00:36 -0800235WiFiEndpoint *WiFiEndpoint::MakeOpenEndpoint(ProxyFactory *proxy_factory,
236 const WiFiRefPtr &wifi,
237 const string &ssid,
mukesh agrawale1d90e92012-02-15 17:36:08 -0800238 const string &bssid,
Paul Stewart3c504012013-01-17 17:49:58 -0800239 const string &network_mode,
mukesh agrawale1d90e92012-02-15 17:36:08 -0800240 uint16 frequency,
241 int16 signal_dbm) {
mukesh agrawal43970a22013-02-15 16:00:07 -0800242 return MakeEndpoint(proxy_factory, wifi, ssid, bssid, network_mode,
243 frequency, signal_dbm, false, false);
244}
245
246// static
247WiFiEndpoint *WiFiEndpoint::MakeEndpoint(ProxyFactory *proxy_factory,
248 const WiFiRefPtr &wifi,
249 const string &ssid,
250 const string &bssid,
251 const string &network_mode,
252 uint16 frequency,
253 int16 signal_dbm,
254 bool has_wpa_property,
255 bool has_rsn_property) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000256 map <string, ::DBus::Variant> args;
257 ::DBus::MessageIter writer;
258
Paul Stewart0654ece2013-03-26 15:21:26 -0700259 writer = args[WPASupplicant::kBSSPropertySSID].writer();
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000260 writer << vector<uint8_t>(ssid.begin(), ssid.end());
261
262 string bssid_nosep;
263 RemoveChars(bssid, ":", &bssid_nosep);
264 vector<uint8_t> bssid_bytes;
265 base::HexStringToBytes(bssid_nosep, &bssid_bytes);
Paul Stewart0654ece2013-03-26 15:21:26 -0700266 writer = args[WPASupplicant::kBSSPropertyBSSID].writer();
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000267 writer << bssid_bytes;
268
Paul Stewart0654ece2013-03-26 15:21:26 -0700269 args[WPASupplicant::kBSSPropertySignal].writer().append_int16(signal_dbm);
270 args[WPASupplicant::kBSSPropertyFrequency].writer().append_uint16(frequency);
271 args[WPASupplicant::kBSSPropertyMode].writer().append_string(
Paul Stewart3c504012013-01-17 17:49:58 -0800272 network_mode.c_str());
mukesh agrawal43970a22013-02-15 16:00:07 -0800273
274 if (has_wpa_property) {
275 ::DBus::MessageIter writer; // local is required; see HACKING
276 map <string, string> empty_dict;
Paul Stewart0654ece2013-03-26 15:21:26 -0700277 writer = args[WPASupplicant::kPropertyWPA].writer();
mukesh agrawal43970a22013-02-15 16:00:07 -0800278 writer << empty_dict;
279 }
280 if (has_rsn_property) {
281 ::DBus::MessageIter writer; // local is required; see HACKING
282 map <string, string> empty_dict;
Paul Stewart0654ece2013-03-26 15:21:26 -0700283 writer = args[WPASupplicant::kPropertyRSN].writer();
mukesh agrawal43970a22013-02-15 16:00:07 -0800284 writer << empty_dict;
285 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000286
mukesh agrawalb20776f2012-02-10 16:00:36 -0800287 return new WiFiEndpoint(
288 proxy_factory, wifi, bssid, args); // |bssid| fakes an RPC ID
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000289}
290
291// static
mukesh agrawal6e277772011-09-29 15:04:23 -0700292const char *WiFiEndpoint::ParseMode(const string &mode_string) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700293 if (mode_string == WPASupplicant::kNetworkModeInfrastructure) {
Chris Masone092df3e2011-08-22 09:41:39 -0700294 return flimflam::kModeManaged;
Paul Stewart0654ece2013-03-26 15:21:26 -0700295 } else if (mode_string == WPASupplicant::kNetworkModeAdHoc) {
Chris Masone092df3e2011-08-22 09:41:39 -0700296 return flimflam::kModeAdhoc;
Paul Stewart0654ece2013-03-26 15:21:26 -0700297 } else if (mode_string == WPASupplicant::kNetworkModeAccessPoint) {
Chris Masone092df3e2011-08-22 09:41:39 -0700298 NOTREACHED() << "Shill does not support AP mode at this time.";
299 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700300 } else {
Chris Masone092df3e2011-08-22 09:41:39 -0700301 NOTREACHED() << "Unknown WiFi endpoint mode!";
302 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700303 }
304}
305
mukesh agrawal6e277772011-09-29 15:04:23 -0700306// static
307const char *WiFiEndpoint::ParseSecurity(
Paul Stewartaffc0552013-03-25 07:50:15 -0700308 const map<string, ::DBus::Variant> &properties, SecurityFlags *flags) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700309 if (ContainsKey(properties, WPASupplicant::kPropertyRSN)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700310 // TODO(quiche): check type before casting
311 const map<string, ::DBus::Variant> rsn_properties(
Paul Stewart0654ece2013-03-26 15:21:26 -0700312 properties.find(WPASupplicant::kPropertyRSN)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700313 operator map<string, ::DBus::Variant>());
Paul Stewartaffc0552013-03-25 07:50:15 -0700314 set<KeyManagement> key_management;
315 ParseKeyManagementMethods(rsn_properties, &key_management);
316 flags->rsn_8021x = ContainsKey(key_management, kKeyManagement802_1x);
317 flags->rsn_psk = ContainsKey(key_management, kKeyManagementPSK);
mukesh agrawal6e277772011-09-29 15:04:23 -0700318 }
319
Paul Stewart0654ece2013-03-26 15:21:26 -0700320 if (ContainsKey(properties, WPASupplicant::kPropertyWPA)) {
mukesh agrawal165e6142011-11-22 02:22:56 +0000321 // TODO(quiche): check type before casting
mukesh agrawal6e277772011-09-29 15:04:23 -0700322 const map<string, ::DBus::Variant> rsn_properties(
Paul Stewart0654ece2013-03-26 15:21:26 -0700323 properties.find(WPASupplicant::kPropertyWPA)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700324 operator map<string, ::DBus::Variant>());
Paul Stewartaffc0552013-03-25 07:50:15 -0700325 set<KeyManagement> key_management;
326 ParseKeyManagementMethods(rsn_properties, &key_management);
327 flags->wpa_8021x = ContainsKey(key_management, kKeyManagement802_1x);
328 flags->wpa_psk = ContainsKey(key_management, kKeyManagementPSK);
mukesh agrawal6e277772011-09-29 15:04:23 -0700329 }
330
Paul Stewart0654ece2013-03-26 15:21:26 -0700331 if (ContainsKey(properties, WPASupplicant::kPropertyPrivacy)) {
Paul Stewartaffc0552013-03-25 07:50:15 -0700332 flags->privacy = properties.find(WPASupplicant::kPropertyPrivacy)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700333 reader().get_bool();
334 }
335
Paul Stewartaffc0552013-03-25 07:50:15 -0700336 if (flags->rsn_8021x || flags->wpa_8021x) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700337 return flimflam::kSecurity8021x;
Paul Stewartaffc0552013-03-25 07:50:15 -0700338 } else if (flags->rsn_psk) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700339 return flimflam::kSecurityRsn;
Paul Stewartaffc0552013-03-25 07:50:15 -0700340 } else if (flags->wpa_psk) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700341 return flimflam::kSecurityWpa;
Paul Stewartaffc0552013-03-25 07:50:15 -0700342 } else if (flags->privacy) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700343 return flimflam::kSecurityWep;
344 } else {
345 return flimflam::kSecurityNone;
346 }
347}
348
349// static
350void WiFiEndpoint::ParseKeyManagementMethods(
351 const map<string, ::DBus::Variant> &security_method_properties,
352 set<KeyManagement> *key_management_methods) {
353 if (!ContainsKey(security_method_properties,
Paul Stewart0654ece2013-03-26 15:21:26 -0700354 WPASupplicant::kSecurityMethodPropertyKeyManagement)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700355 return;
356 }
357
358 // TODO(quiche): check type before cast
359 const vector<string> key_management_vec =
360 security_method_properties.
Paul Stewart0654ece2013-03-26 15:21:26 -0700361 find(WPASupplicant::kSecurityMethodPropertyKeyManagement)->second.
mukesh agrawal6e277772011-09-29 15:04:23 -0700362 operator vector<string>();
363 for (vector<string>::const_iterator it = key_management_vec.begin();
364 it != key_management_vec.end();
365 ++it) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700366 if (EndsWith(*it, WPASupplicant::kKeyManagementMethodSuffixEAP, true)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700367 key_management_methods->insert(kKeyManagement802_1x);
368 } else if (
Paul Stewart0654ece2013-03-26 15:21:26 -0700369 EndsWith(*it, WPASupplicant::kKeyManagementMethodSuffixPSK, true)) {
mukesh agrawal6e277772011-09-29 15:04:23 -0700370 key_management_methods->insert(kKeyManagementPSK);
371 }
372 }
373}
374
Thieu Le1df7f4e2012-02-10 15:21:45 -0800375// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700376Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyModeFromFrequency(
Thieu Le1df7f4e2012-02-10 15:21:45 -0800377 const map<string, ::DBus::Variant> &properties, uint16 frequency) {
378 uint32_t max_rate = 0;
379 map<string, ::DBus::Variant>::const_iterator it =
Paul Stewart0654ece2013-03-26 15:21:26 -0700380 properties.find(WPASupplicant::kBSSPropertyRates);
Thieu Le1df7f4e2012-02-10 15:21:45 -0800381 if (it != properties.end()) {
382 vector<uint32_t> rates = it->second.operator vector<uint32_t>();
383 if (rates.size() > 0)
384 max_rate = rates[0]; // Rates are sorted in descending order
385 }
386
387 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
Thieu Le1df7f4e2012-02-10 15:21:45 -0800388 if (frequency < 3000) {
389 // 2.4GHz legacy, check for tx rate for 11b-only
390 // (note 22M is valid)
391 if (max_rate < 24000000)
392 phy_mode = Metrics::kWiFiNetworkPhyMode11b;
393 else
394 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
395 } else {
396 phy_mode = Metrics::kWiFiNetworkPhyMode11a;
397 }
398
399 return phy_mode;
400}
401
402// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700403bool WiFiEndpoint::ParseIEs(
404 const map<string, ::DBus::Variant> &properties,
405 Metrics::WiFiNetworkPhyMode *phy_mode,
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800406 VendorInformation *vendor_information,
Paul Stewartbdbd3c32013-04-17 09:47:21 -0700407 bool *ieee80211w_required, string *country_code) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700408
409 map<string, ::DBus::Variant>::const_iterator ies_property =
Paul Stewart0654ece2013-03-26 15:21:26 -0700410 properties.find(WPASupplicant::kBSSPropertyIEs);
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700411 if (ies_property == properties.end()) {
412 SLOG(WiFi, 2) << __func__ << ": No IE property in BSS.";
413 return false;
Thieu Le1df7f4e2012-02-10 15:21:45 -0800414 }
415
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700416 vector<uint8_t> ies = ies_property->second.operator vector<uint8_t>();
417
418
419 // Format of an information element:
420 // 1 1 1 - 252
421 // +------+--------+----------------+
422 // | Type | Length | Data |
423 // +------+--------+----------------+
424 *phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
425 bool found_ht = false;
426 bool found_erp = false;
427 int ie_len = 0;
428 vector<uint8_t>::iterator it;
429 for (it = ies.begin();
430 std::distance(it, ies.end()) > 1; // Ensure Length field is within PDU.
431 it += ie_len) {
432 ie_len = 2 + *(it + 1);
433 if (std::distance(it, ies.end()) < ie_len) {
434 LOG(ERROR) << __func__ << ": IE extends past containing PDU.";
435 break;
436 }
437 switch (*it) {
Paul Stewartbdbd3c32013-04-17 09:47:21 -0700438 case IEEE_80211::kElemIdCountry:
439 // Retrieve 2-character country code from the beginning of the element.
440 if (ie_len >= 4) {
441 *country_code = string(it + 2, it + 4);
442 }
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700443 case IEEE_80211::kElemIdErp:
444 if (!found_ht) {
445 *phy_mode = Metrics::kWiFiNetworkPhyMode11g;
446 }
447 found_erp = true;
448 break;
449 case IEEE_80211::kElemIdHTCap:
450 case IEEE_80211::kElemIdHTInfo:
451 *phy_mode = Metrics::kWiFiNetworkPhyMode11n;
452 found_ht = true;
453 break;
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800454 case IEEE_80211::kElemIdRSN:
455 ParseWPACapabilities(it + 2, it + ie_len, ieee80211w_required);
456 break;
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700457 case IEEE_80211::kElemIdVendor:
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800458 ParseVendorIE(it + 2, it + ie_len, vendor_information,
459 ieee80211w_required);
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700460 break;
461 }
462 }
463 return found_ht || found_erp;
464}
465
466// static
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800467void WiFiEndpoint::ParseWPACapabilities(
468 vector<uint8_t>::const_iterator ie,
469 vector<uint8_t>::const_iterator end,
470 bool *ieee80211w_required) {
471 // Format of an RSN Information Element:
472 // 2 4
473 // +------+--------------------+
474 // | Type | Group Cipher Suite |
475 // +------+--------------------+
476 // 2 4 * pairwise count
477 // +-----------------------+---------------------+
478 // | Pairwise Cipher Count | Pairwise Ciphers... |
479 // +-----------------------+---------------------+
480 // 2 4 * authkey count
481 // +-----------------------+---------------------+
482 // | AuthKey Suite Count | AuthKey Suites... |
483 // +-----------------------+---------------------+
484 // 2
485 // +------------------+
486 // | RSN Capabilities |
487 // +------------------+
488 // 2 16 * pmkid count
489 // +------------------+-------------------+
490 // | PMKID Count | PMKIDs... |
491 // +------------------+-------------------+
492 // 4
493 // +-------------------------------+
494 // | Group Management Cipher Suite |
495 // +-------------------------------+
496 if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountOffset) {
497 return;
498 }
499 ie += IEEE_80211::kRSNIECipherCountOffset;
500
501 // Advance past the pairwise and authkey ciphers. Each is a little-endian
502 // cipher count followed by n * cipher_selector.
503 for (int i = 0; i < IEEE_80211::kRSNIENumCiphers; ++i) {
504 // Retrieve a little-endian cipher count.
505 if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountLen) {
506 return;
507 }
508 uint16 cipher_count = *ie | (*(ie + 1) << 8);
509
510 // Skip over the cipher selectors.
511 int skip_length = IEEE_80211::kRSNIECipherCountLen +
512 cipher_count * IEEE_80211::kRSNIESelectorLen;
513 if (std::distance(ie, end) < skip_length) {
514 return;
515 }
516 ie += skip_length;
517 }
518
519 if (std::distance(ie, end) < IEEE_80211::kRSNIECapabilitiesLen) {
520 return;
521 }
522
523 // Retrieve a little-endian capabilities bitfield.
524 uint16 capabilities = *ie | (*(ie + 1) << 8);
525
526 if (capabilities & IEEE_80211::kRSNCapabilityFrameProtectionRequired &&
527 ieee80211w_required) {
528 // Never set this value to false, since there may be multiple RSN
529 // information elements.
530 *ieee80211w_required = true;
531 }
532}
533
534
535// static
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700536void WiFiEndpoint::ParseVendorIE(vector<uint8_t>::const_iterator ie,
537 vector<uint8_t>::const_iterator end,
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800538 VendorInformation *vendor_information,
539 bool *ieee80211w_required) {
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700540 // Format of an vendor-specific information element (with type
541 // and length field for the IE removed by the caller):
542 // 3 1 1 - 248
543 // +------------+----------+----------------+
544 // | OUI | OUI Type | Data |
545 // +------------+----------+----------------+
546
547 if (std::distance(ie, end) < 4) {
548 LOG(ERROR) << __func__ << ": no room in IE for OUI and type field.";
549 return;
550 }
551 uint32_t oui = (*ie << 16) | (*(ie + 1) << 8) | *(ie + 2);
552 uint8_t oui_type = *(ie + 3);
553 ie += 4;
554
555 if (oui == IEEE_80211::kOUIVendorMicrosoft &&
556 oui_type == IEEE_80211::kOUIMicrosoftWPS) {
557 // Format of a WPS data element:
558 // 2 2
559 // +------+--------+----------------+
560 // | Type | Length | Data |
561 // +------+--------+----------------+
562 while (std::distance(ie, end) >= 4) {
563 int element_type = (*ie << 8) | *(ie + 1);
564 int element_length = (*(ie + 2) << 8) | *(ie + 3);
565 ie += 4;
566 if (std::distance(ie, end) < element_length) {
567 LOG(ERROR) << __func__ << ": WPS element extends past containing PDU.";
568 break;
569 }
570 string s(ie, ie + element_length);
571 if (IsStringASCII(s)) {
572 switch (element_type) {
573 case IEEE_80211::kWPSElementManufacturer:
574 vendor_information->wps_manufacturer = s;
575 break;
576 case IEEE_80211::kWPSElementModelName:
577 vendor_information->wps_model_name = s;
578 break;
579 case IEEE_80211::kWPSElementModelNumber:
580 vendor_information->wps_model_number = s;
581 break;
582 case IEEE_80211::kWPSElementDeviceName:
583 vendor_information->wps_device_name = s;
584 break;
585 }
586 }
587 ie += element_length;
588 }
Paul Stewarta5e7d5f2013-01-09 18:06:15 -0800589 } else if (oui == IEEE_80211::kOUIVendorMicrosoft &&
590 oui_type == IEEE_80211::kOUIMicrosoftWPA) {
591 ParseWPACapabilities(ie, end, ieee80211w_required);
Paul Stewart72b2fdc2012-06-02 08:58:51 -0700592 } else if (oui != IEEE_80211::kOUIVendorEpigram &&
593 oui != IEEE_80211::kOUIVendorMicrosoft) {
594 vendor_information->oui_list.insert(oui);
595 }
Thieu Le1df7f4e2012-02-10 15:21:45 -0800596}
597
mukesh agrawalb54601c2011-06-07 17:39:22 -0700598} // namespace shill