blob: a36ad455c6b11b3a7141b2a00e573532c54aa3de [file] [log] [blame]
Thieu Lee41a72d2012-02-06 20:46:51 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
mukesh agrawalb54601c2011-06-07 17:39:22 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone092df3e2011-08-22 09:41:39 -07005#include "shill/wifi_endpoint.h"
6
7#include <base/logging.h>
mukesh agrawal6e277772011-09-29 15:04:23 -07008#include <base/stl_util-inl.h>
mukesh agrawalb54601c2011-06-07 17:39:22 -07009#include <base/stringprintf.h>
10#include <base/string_number_conversions.h>
mukesh agrawal6e277772011-09-29 15:04:23 -070011#include <base/string_util.h>
Chris Masone092df3e2011-08-22 09:41:39 -070012#include <chromeos/dbus/service_constants.h>
mukesh agrawalb54601c2011-06-07 17:39:22 -070013
Thieu Le1df7f4e2012-02-10 15:21:45 -080014#include "shill/ieee80211.h"
mukesh agrawal16bc1b82012-02-09 18:38:26 -080015#include "shill/wifi.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070016#include "shill/wpa_supplicant.h"
17
18using std::map;
19using std::set;
mukesh agrawalb54601c2011-06-07 17:39:22 -070020using std::string;
mukesh agrawal6e277772011-09-29 15:04:23 -070021using std::vector;
mukesh agrawalb54601c2011-06-07 17:39:22 -070022
23namespace shill {
24
mukesh agrawalb54601c2011-06-07 17:39:22 -070025WiFiEndpoint::WiFiEndpoint(
Thieu Lee41a72d2012-02-06 20:46:51 +000026 const map<string, ::DBus::Variant> &properties)
27 : frequency_(0) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070028 // XXX will segfault on missing properties
29 ssid_ =
mukesh agrawal6e277772011-09-29 15:04:23 -070030 properties.find(wpa_supplicant::kBSSPropertySSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070031 operator std::vector<uint8_t>();
32 bssid_ =
mukesh agrawal6e277772011-09-29 15:04:23 -070033 properties.find(wpa_supplicant::kBSSPropertyBSSID)->second.
mukesh agrawalb54601c2011-06-07 17:39:22 -070034 operator std::vector<uint8_t>();
35 signal_strength_ =
mukesh agrawal15908392011-11-16 18:29:25 +000036 properties.find(wpa_supplicant::kBSSPropertySignal)->second.
37 reader().get_int16();
Thieu Lee41a72d2012-02-06 20:46:51 +000038 map<string, ::DBus::Variant>::const_iterator it =
39 properties.find(wpa_supplicant::kBSSPropertyFrequency);
40 if (it != properties.end())
41 frequency_ = it->second.reader().get_uint16();
Thieu Le1df7f4e2012-02-10 15:21:45 -080042 physical_mode_ = DeterminePhyMode(properties, frequency_);
Chris Masone092df3e2011-08-22 09:41:39 -070043 network_mode_ = ParseMode(
mukesh agrawal6e277772011-09-29 15:04:23 -070044 properties.find(wpa_supplicant::kBSSPropertyMode)->second);
45 security_mode_ = ParseSecurity(properties);
mukesh agrawalb54601c2011-06-07 17:39:22 -070046
Chris Masone092df3e2011-08-22 09:41:39 -070047 if (network_mode_.empty()) {
mukesh agrawalb54601c2011-06-07 17:39:22 -070048 // XXX log error?
49 }
50
51 ssid_string_ = string(ssid_.begin(), ssid_.end());
mukesh agrawal16bc1b82012-02-09 18:38:26 -080052 WiFi::SanitizeSSID(&ssid_string_);
mukesh agrawalb54601c2011-06-07 17:39:22 -070053 ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size());
54 bssid_string_ = StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x",
55 bssid_[0], bssid_[1], bssid_[2],
56 bssid_[3], bssid_[4], bssid_[5]);
57 bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size());
58}
59
60WiFiEndpoint::~WiFiEndpoint() {}
61
Chris Masone092df3e2011-08-22 09:41:39 -070062// static
63uint32_t WiFiEndpoint::ModeStringToUint(const std::string &mode_string) {
64 if (mode_string == flimflam::kModeManaged)
mukesh agrawal6e277772011-09-29 15:04:23 -070065 return wpa_supplicant::kNetworkModeInfrastructureInt;
Chris Masone092df3e2011-08-22 09:41:39 -070066 else if (mode_string == flimflam::kModeAdhoc)
mukesh agrawal6e277772011-09-29 15:04:23 -070067 return wpa_supplicant::kNetworkModeAdHocInt;
Chris Masone092df3e2011-08-22 09:41:39 -070068 else
69 NOTIMPLEMENTED() << "Shill dos not support " << mode_string
70 << " mode at this time.";
71 return 0;
72}
73
mukesh agrawal6e277772011-09-29 15:04:23 -070074const vector<uint8_t> &WiFiEndpoint::ssid() const {
mukesh agrawalb54601c2011-06-07 17:39:22 -070075 return ssid_;
76}
77
78const string &WiFiEndpoint::ssid_string() const {
79 return ssid_string_;
80}
81
82const string &WiFiEndpoint::ssid_hex() const {
83 return ssid_hex_;
84}
85
86const string &WiFiEndpoint::bssid_string() const {
87 return bssid_string_;
88}
89
90const string &WiFiEndpoint::bssid_hex() const {
91 return bssid_hex_;
92}
93
94int16_t WiFiEndpoint::signal_strength() const {
95 return signal_strength_;
96}
97
Thieu Lee41a72d2012-02-06 20:46:51 +000098uint16 WiFiEndpoint::frequency() const {
99 return frequency_;
100}
101
Thieu Le1df7f4e2012-02-10 15:21:45 -0800102uint16 WiFiEndpoint::physical_mode() const {
103 return physical_mode_;
104}
105
Chris Masone092df3e2011-08-22 09:41:39 -0700106const string &WiFiEndpoint::network_mode() const {
mukesh agrawal6e277772011-09-29 15:04:23 -0700107 return network_mode_;
108}
109
110const string &WiFiEndpoint::security_mode() const {
111 return security_mode_;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700112}
113
Chris Masone092df3e2011-08-22 09:41:39 -0700114// static
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000115WiFiEndpoint *WiFiEndpoint::MakeOpenEndpoint(
116 const string &ssid, const string &bssid) {
117 map <string, ::DBus::Variant> args;
118 ::DBus::MessageIter writer;
119
120 writer = args[wpa_supplicant::kBSSPropertySSID].writer();
121 writer << vector<uint8_t>(ssid.begin(), ssid.end());
122
123 string bssid_nosep;
124 RemoveChars(bssid, ":", &bssid_nosep);
125 vector<uint8_t> bssid_bytes;
126 base::HexStringToBytes(bssid_nosep, &bssid_bytes);
127 writer = args[wpa_supplicant::kBSSPropertyBSSID].writer();
128 writer << bssid_bytes;
129
130 args[wpa_supplicant::kBSSPropertySignal].writer().append_int16(0);
131 args[wpa_supplicant::kBSSPropertyMode].writer().append_string(
132 wpa_supplicant::kNetworkModeInfrastructure);
133 // We indicate this is an open BSS by leaving out all security properties.
134
135 return new WiFiEndpoint(args);
136}
137
138// static
mukesh agrawal6e277772011-09-29 15:04:23 -0700139const char *WiFiEndpoint::ParseMode(const string &mode_string) {
140 if (mode_string == wpa_supplicant::kNetworkModeInfrastructure) {
Chris Masone092df3e2011-08-22 09:41:39 -0700141 return flimflam::kModeManaged;
mukesh agrawal6e277772011-09-29 15:04:23 -0700142 } else if (mode_string == wpa_supplicant::kNetworkModeAdHoc) {
Chris Masone092df3e2011-08-22 09:41:39 -0700143 return flimflam::kModeAdhoc;
mukesh agrawal6e277772011-09-29 15:04:23 -0700144 } else if (mode_string == wpa_supplicant::kNetworkModeAccessPoint) {
Chris Masone092df3e2011-08-22 09:41:39 -0700145 NOTREACHED() << "Shill does not support AP mode at this time.";
146 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700147 } else {
Chris Masone092df3e2011-08-22 09:41:39 -0700148 NOTREACHED() << "Unknown WiFi endpoint mode!";
149 return NULL;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700150 }
151}
152
mukesh agrawal6e277772011-09-29 15:04:23 -0700153// static
154const char *WiFiEndpoint::ParseSecurity(
155 const map<string, ::DBus::Variant> &properties) {
156 set<KeyManagement> rsn_key_management_methods;
157 if (ContainsKey(properties, wpa_supplicant::kPropertyRSN)) {
158 // TODO(quiche): check type before casting
159 const map<string, ::DBus::Variant> rsn_properties(
160 properties.find(wpa_supplicant::kPropertyRSN)->second.
161 operator map<string, ::DBus::Variant>());
162 ParseKeyManagementMethods(rsn_properties, &rsn_key_management_methods);
163 }
164
165 set<KeyManagement> wpa_key_management_methods;
166 if (ContainsKey(properties, wpa_supplicant::kPropertyWPA)) {
mukesh agrawal165e6142011-11-22 02:22:56 +0000167 // TODO(quiche): check type before casting
mukesh agrawal6e277772011-09-29 15:04:23 -0700168 const map<string, ::DBus::Variant> rsn_properties(
169 properties.find(wpa_supplicant::kPropertyWPA)->second.
170 operator map<string, ::DBus::Variant>());
171 ParseKeyManagementMethods(rsn_properties, &wpa_key_management_methods);
172 }
173
174 bool wep_privacy = false;
175 if (ContainsKey(properties, wpa_supplicant::kPropertyPrivacy)) {
176 wep_privacy = properties.find(wpa_supplicant::kPropertyPrivacy)->second.
177 reader().get_bool();
178 }
179
180 if (ContainsKey(rsn_key_management_methods, kKeyManagement802_1x) ||
181 ContainsKey(wpa_key_management_methods, kKeyManagement802_1x)) {
182 return flimflam::kSecurity8021x;
183 } else if (ContainsKey(rsn_key_management_methods, kKeyManagementPSK)) {
184 return flimflam::kSecurityRsn;
185 } else if (ContainsKey(wpa_key_management_methods, kKeyManagementPSK)) {
186 return flimflam::kSecurityWpa;
187 } else if (wep_privacy) {
188 return flimflam::kSecurityWep;
189 } else {
190 return flimflam::kSecurityNone;
191 }
192}
193
194// static
195void WiFiEndpoint::ParseKeyManagementMethods(
196 const map<string, ::DBus::Variant> &security_method_properties,
197 set<KeyManagement> *key_management_methods) {
198 if (!ContainsKey(security_method_properties,
199 wpa_supplicant::kSecurityMethodPropertyKeyManagement)) {
200 return;
201 }
202
203 // TODO(quiche): check type before cast
204 const vector<string> key_management_vec =
205 security_method_properties.
206 find(wpa_supplicant::kSecurityMethodPropertyKeyManagement)->second.
207 operator vector<string>();
208 for (vector<string>::const_iterator it = key_management_vec.begin();
209 it != key_management_vec.end();
210 ++it) {
211 if (EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixEAP, true)) {
212 key_management_methods->insert(kKeyManagement802_1x);
213 } else if (
214 EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixPSK, true)) {
215 key_management_methods->insert(kKeyManagementPSK);
216 }
217 }
218}
219
Thieu Le1df7f4e2012-02-10 15:21:45 -0800220// static
221Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyMode(
222 const map<string, ::DBus::Variant> &properties, uint16 frequency) {
223 uint32_t max_rate = 0;
224 map<string, ::DBus::Variant>::const_iterator it =
225 properties.find(wpa_supplicant::kBSSPropertyRates);
226 if (it != properties.end()) {
227 vector<uint32_t> rates = it->second.operator vector<uint32_t>();
228 if (rates.size() > 0)
229 max_rate = rates[0]; // Rates are sorted in descending order
230 }
231
232 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
233 it = properties.find(wpa_supplicant::kBSSPropertyIEs);
234 if (it != properties.end()) {
235 phy_mode = ParseIEsForPhyMode(it->second.operator vector<uint8_t>());
236 if (phy_mode != Metrics::kWiFiNetworkPhyModeUndef)
237 return phy_mode;
238 }
239
240 if (frequency < 3000) {
241 // 2.4GHz legacy, check for tx rate for 11b-only
242 // (note 22M is valid)
243 if (max_rate < 24000000)
244 phy_mode = Metrics::kWiFiNetworkPhyMode11b;
245 else
246 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
247 } else {
248 phy_mode = Metrics::kWiFiNetworkPhyMode11a;
249 }
250
251 return phy_mode;
252}
253
254// static
255Metrics::WiFiNetworkPhyMode WiFiEndpoint::ParseIEsForPhyMode(
256 const vector<uint8_t> &ies) {
257 // Format of an information element:
258 // 1 1 3 1 - 252
259 // +------+--------+------------+----------------+
260 // | Type | Length | OUI | Data |
261 // +------+--------+------------+----------------+
262 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
263 vector<uint8_t>::const_iterator it;
264 for (it = ies.begin();
265 it + 1 < ies.end(); // +1 to ensure Length field is in valid memory
266 it += 2 + *(it + 1)) {
267 if (*it == IEEE_80211::kElemIdErp) {
268 phy_mode = Metrics::kWiFiNetworkPhyMode11g;
269 continue; // NB: Continue to check for HT
270 }
271 if (*it == IEEE_80211::kElemIdHTCap || *it == IEEE_80211::kElemIdHTInfo) {
272 phy_mode = Metrics::kWiFiNetworkPhyMode11n;
273 break;
274 }
275 }
276
277 return phy_mode;
278}
279
mukesh agrawalb54601c2011-06-07 17:39:22 -0700280} // namespace shill