1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "shill/wifi/wifi_endpoint.h" 18 19 #include <algorithm> 20 21 #include <base/stl_util.h> 22 #include <base/strings/stringprintf.h> 23 #include <base/strings/string_number_conversions.h> 24 #include <base/strings/string_util.h> 25 #if defined(__ANDROID__) 26 #include <dbus/service_constants.h> 27 #else 28 #include <chromeos/dbus/service_constants.h> 29 #endif // __ANDROID__ 30 31 #include "shill/control_interface.h" 32 #include "shill/logging.h" 33 #include "shill/metrics.h" 34 #include "shill/net/ieee80211.h" 35 #include "shill/supplicant/supplicant_bss_proxy_interface.h" 36 #include "shill/supplicant/wpa_supplicant.h" 37 #include "shill/tethering.h" 38 #include "shill/wifi/wifi.h" 39 40 using base::StringPrintf; 41 using std::map; 42 using std::set; 43 using std::string; 44 using std::vector; 45 46 namespace shill { 47 48 namespace Logging { 49 static auto kModuleLogScope = ScopeLogger::kWiFi; 50 static string ObjectID(WiFiEndpoint* w) { return "(wifi_endpoint)"; } 51 } 52 53 WiFiEndpoint::WiFiEndpoint(ControlInterface* control_interface, 54 const WiFiRefPtr& device, 55 const string& rpc_id, 56 const KeyValueStore& properties) 57 : frequency_(0), 58 physical_mode_(Metrics::kWiFiNetworkPhyModeUndef), 59 ieee80211w_required_(false), 60 control_interface_(control_interface), 61 device_(device), 62 rpc_id_(rpc_id) { 63 ssid_ = properties.GetUint8s(WPASupplicant::kBSSPropertySSID); 64 bssid_ = properties.GetUint8s(WPASupplicant::kBSSPropertyBSSID); 65 signal_strength_ = properties.GetInt16(WPASupplicant::kBSSPropertySignal); 66 if (properties.ContainsUint16(WPASupplicant::kBSSPropertyFrequency)) { 67 frequency_ = properties.GetUint16(WPASupplicant::kBSSPropertyFrequency); 68 } 69 70 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef; 71 if (!ParseIEs(properties, &phy_mode, &vendor_information_, 72 &ieee80211w_required_, &country_code_)) { 73 phy_mode = DeterminePhyModeFromFrequency(properties, frequency_); 74 } 75 physical_mode_ = phy_mode; 76 77 network_mode_ = ParseMode( 78 properties.GetString(WPASupplicant::kBSSPropertyMode)); 79 set_security_mode(ParseSecurity(properties, &security_flags_)); 80 has_rsn_property_ = 81 properties.ContainsKeyValueStore(WPASupplicant::kPropertyRSN); 82 has_wpa_property_ = 83 properties.ContainsKeyValueStore(WPASupplicant::kPropertyWPA); 84 85 if (network_mode_.empty()) { 86 // XXX log error? 87 } 88 89 ssid_string_ = string(ssid_.begin(), ssid_.end()); 90 WiFi::SanitizeSSID(&ssid_string_); 91 ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size()); 92 bssid_string_ = Device::MakeStringFromHardwareAddress(bssid_); 93 bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size()); 94 95 CheckForTetheringSignature(); 96 } 97 98 WiFiEndpoint::~WiFiEndpoint() {} 99 100 void WiFiEndpoint::Start() { 101 supplicant_bss_proxy_.reset( 102 control_interface_->CreateSupplicantBSSProxy(this, rpc_id_)); 103 } 104 105 void WiFiEndpoint::PropertiesChanged(const KeyValueStore& properties) { 106 SLOG(this, 2) << __func__; 107 bool should_notify = false; 108 if (properties.ContainsInt16(WPASupplicant::kBSSPropertySignal)) { 109 signal_strength_ = properties.GetInt16(WPASupplicant::kBSSPropertySignal); 110 should_notify = true; 111 } 112 113 if (properties.ContainsString(WPASupplicant::kBSSPropertyMode)) { 114 string new_mode = 115 ParseMode(properties.GetString(WPASupplicant::kBSSPropertyMode)); 116 if (new_mode != network_mode_) { 117 network_mode_ = new_mode; 118 SLOG(this, 2) << "WiFiEndpoint " << bssid_string_ << " mode is now " 119 << network_mode_; 120 should_notify = true; 121 } 122 } 123 124 const char* new_security_mode = ParseSecurity(properties, &security_flags_); 125 if (new_security_mode != security_mode()) { 126 set_security_mode(new_security_mode); 127 SLOG(this, 2) << "WiFiEndpoint " << bssid_string_ << " security is now " 128 << security_mode(); 129 should_notify = true; 130 } 131 132 if (should_notify) { 133 device_->NotifyEndpointChanged(this); 134 } 135 } 136 137 void WiFiEndpoint::UpdateSignalStrength(int16_t strength) { 138 if (signal_strength_ == strength) { 139 return; 140 } 141 142 SLOG(this, 2) << __func__ << ": signal strength " 143 << signal_strength_ << " -> " << strength; 144 signal_strength_ = strength; 145 device_->NotifyEndpointChanged(this); 146 } 147 148 map<string, string> WiFiEndpoint::GetVendorInformation() const { 149 map<string, string> vendor_information; 150 if (!vendor_information_.wps_manufacturer.empty()) { 151 vendor_information[kVendorWPSManufacturerProperty] = 152 vendor_information_.wps_manufacturer; 153 } 154 if (!vendor_information_.wps_model_name.empty()) { 155 vendor_information[kVendorWPSModelNameProperty] = 156 vendor_information_.wps_model_name; 157 } 158 if (!vendor_information_.wps_model_number.empty()) { 159 vendor_information[kVendorWPSModelNumberProperty] = 160 vendor_information_.wps_model_number; 161 } 162 if (!vendor_information_.wps_device_name.empty()) { 163 vendor_information[kVendorWPSDeviceNameProperty] = 164 vendor_information_.wps_device_name; 165 } 166 if (!vendor_information_.oui_set.empty()) { 167 vector<string> oui_vector; 168 for (auto oui : vendor_information_.oui_set) { 169 oui_vector.push_back( 170 StringPrintf("%02x-%02x-%02x", 171 oui >> 16, (oui >> 8) & 0xff, oui & 0xff)); 172 } 173 vendor_information[kVendorOUIListProperty] = 174 base::JoinString(oui_vector, " "); 175 } 176 return vendor_information; 177 } 178 179 // static 180 uint32_t WiFiEndpoint::ModeStringToUint(const string& mode_string) { 181 if (mode_string == kModeManaged) 182 return WPASupplicant::kNetworkModeInfrastructureInt; 183 else if (mode_string == kModeAdhoc) 184 return WPASupplicant::kNetworkModeAdHocInt; 185 else 186 NOTIMPLEMENTED() << "Shill dos not support " << mode_string 187 << " mode at this time."; 188 return 0; 189 } 190 191 const vector<uint8_t>& WiFiEndpoint::ssid() const { 192 return ssid_; 193 } 194 195 const string& WiFiEndpoint::ssid_string() const { 196 return ssid_string_; 197 } 198 199 const string& WiFiEndpoint::ssid_hex() const { 200 return ssid_hex_; 201 } 202 203 const string& WiFiEndpoint::bssid_string() const { 204 return bssid_string_; 205 } 206 207 const string& WiFiEndpoint::bssid_hex() const { 208 return bssid_hex_; 209 } 210 211 const string& WiFiEndpoint::country_code() const { 212 return country_code_; 213 } 214 215 const WiFiRefPtr& WiFiEndpoint::device() const { 216 return device_; 217 } 218 219 int16_t WiFiEndpoint::signal_strength() const { 220 return signal_strength_; 221 } 222 223 uint16_t WiFiEndpoint::frequency() const { 224 return frequency_; 225 } 226 227 uint16_t WiFiEndpoint::physical_mode() const { 228 return physical_mode_; 229 } 230 231 const string& WiFiEndpoint::network_mode() const { 232 return network_mode_; 233 } 234 235 const string& WiFiEndpoint::security_mode() const { 236 return security_mode_; 237 } 238 239 bool WiFiEndpoint::ieee80211w_required() const { 240 return ieee80211w_required_; 241 } 242 243 bool WiFiEndpoint::has_rsn_property() const { 244 return has_rsn_property_; 245 } 246 247 bool WiFiEndpoint::has_wpa_property() const { 248 return has_wpa_property_; 249 } 250 251 bool WiFiEndpoint::has_tethering_signature() const { 252 return has_tethering_signature_; 253 } 254 255 // static 256 WiFiEndpoint* WiFiEndpoint::MakeOpenEndpoint( 257 ControlInterface* control_interface, 258 const WiFiRefPtr& wifi, 259 const string& ssid, 260 const string& bssid, 261 const string& network_mode, 262 uint16_t frequency, 263 int16_t signal_dbm) { 264 return MakeEndpoint(control_interface, wifi, ssid, bssid, network_mode, 265 frequency, signal_dbm, false, false); 266 } 267 268 269 // static 270 WiFiEndpoint* WiFiEndpoint::MakeEndpoint(ControlInterface* control_interface, 271 const WiFiRefPtr& wifi, 272 const string& ssid, 273 const string& bssid, 274 const string& network_mode, 275 uint16_t frequency, 276 int16_t signal_dbm, 277 bool has_wpa_property, 278 bool has_rsn_property) { 279 KeyValueStore args; 280 281 args.SetUint8s(WPASupplicant::kBSSPropertySSID, 282 vector<uint8_t>(ssid.begin(), ssid.end())); 283 284 vector<uint8_t> bssid_bytes = 285 Device::MakeHardwareAddressFromString(bssid); 286 args.SetUint8s(WPASupplicant::kBSSPropertyBSSID, bssid_bytes); 287 288 args.SetInt16(WPASupplicant::kBSSPropertySignal, signal_dbm); 289 args.SetUint16(WPASupplicant::kBSSPropertyFrequency, frequency); 290 args.SetString(WPASupplicant::kBSSPropertyMode, network_mode); 291 292 if (has_wpa_property) { 293 KeyValueStore empty_args; 294 args.SetKeyValueStore(WPASupplicant::kPropertyWPA, empty_args); 295 } 296 if (has_rsn_property) { 297 KeyValueStore empty_args; 298 args.SetKeyValueStore(WPASupplicant::kPropertyRSN, empty_args); 299 } 300 301 return new WiFiEndpoint( 302 control_interface, wifi, bssid, args); // |bssid| fakes an RPC ID 303 } 304 305 // static 306 const char* WiFiEndpoint::ParseMode(const string& mode_string) { 307 if (mode_string == WPASupplicant::kNetworkModeInfrastructure) { 308 return kModeManaged; 309 } else if (mode_string == WPASupplicant::kNetworkModeAdHoc) { 310 return kModeAdhoc; 311 } else if (mode_string == WPASupplicant::kNetworkModeAccessPoint) { 312 NOTREACHED() << "Shill does not support AP mode at this time."; 313 return nullptr; 314 } else { 315 NOTREACHED() << "Unknown WiFi endpoint mode!"; 316 return nullptr; 317 } 318 } 319 320 // static 321 const char* WiFiEndpoint::ParseSecurity( 322 const KeyValueStore& properties, SecurityFlags* flags) { 323 if (properties.ContainsKeyValueStore(WPASupplicant::kPropertyRSN)) { 324 KeyValueStore rsn_properties = 325 properties.GetKeyValueStore(WPASupplicant::kPropertyRSN); 326 set<KeyManagement> key_management; 327 ParseKeyManagementMethods(rsn_properties, &key_management); 328 flags->rsn_8021x = ContainsKey(key_management, kKeyManagement802_1x); 329 flags->rsn_psk = ContainsKey(key_management, kKeyManagementPSK); 330 } 331 332 if (properties.ContainsKeyValueStore(WPASupplicant::kPropertyWPA)) { 333 KeyValueStore rsn_properties = 334 properties.GetKeyValueStore(WPASupplicant::kPropertyWPA); 335 set<KeyManagement> key_management; 336 ParseKeyManagementMethods(rsn_properties, &key_management); 337 flags->wpa_8021x = ContainsKey(key_management, kKeyManagement802_1x); 338 flags->wpa_psk = ContainsKey(key_management, kKeyManagementPSK); 339 } 340 341 if (properties.ContainsBool(WPASupplicant::kPropertyPrivacy)) { 342 flags->privacy = properties.GetBool(WPASupplicant::kPropertyPrivacy); 343 } 344 345 if (flags->rsn_8021x || flags->wpa_8021x) { 346 return kSecurity8021x; 347 } else if (flags->rsn_psk) { 348 return kSecurityRsn; 349 } else if (flags->wpa_psk) { 350 return kSecurityWpa; 351 } else if (flags->privacy) { 352 return kSecurityWep; 353 } else { 354 return kSecurityNone; 355 } 356 } 357 358 // static 359 void WiFiEndpoint::ParseKeyManagementMethods( 360 const KeyValueStore& security_method_properties, 361 set<KeyManagement>* key_management_methods) { 362 if (!security_method_properties.ContainsStrings( 363 WPASupplicant::kSecurityMethodPropertyKeyManagement)) { 364 return; 365 } 366 367 const vector<string> key_management_vec = 368 security_method_properties.GetStrings( 369 WPASupplicant::kSecurityMethodPropertyKeyManagement); 370 371 for (const auto& method : key_management_vec) { 372 if (base::EndsWith(method, WPASupplicant::kKeyManagementMethodSuffixEAP, 373 base::CompareCase::SENSITIVE)) { 374 key_management_methods->insert(kKeyManagement802_1x); 375 } else if (base::EndsWith(method, 376 WPASupplicant::kKeyManagementMethodSuffixPSK, 377 base::CompareCase::SENSITIVE)) { 378 key_management_methods->insert(kKeyManagementPSK); 379 } 380 } 381 } 382 383 // static 384 Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyModeFromFrequency( 385 const KeyValueStore& properties, uint16_t frequency) { 386 uint32_t max_rate = 0; 387 if (properties.ContainsUint32s(WPASupplicant::kBSSPropertyRates)) { 388 vector<uint32_t> rates = 389 properties.GetUint32s(WPASupplicant::kBSSPropertyRates); 390 if (rates.size() > 0) { 391 max_rate = rates[0]; // Rates are sorted in descending order 392 } 393 } 394 395 Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef; 396 if (frequency < 3000) { 397 // 2.4GHz legacy, check for tx rate for 11b-only 398 // (note 22M is valid) 399 if (max_rate < 24000000) 400 phy_mode = Metrics::kWiFiNetworkPhyMode11b; 401 else 402 phy_mode = Metrics::kWiFiNetworkPhyMode11g; 403 } else { 404 phy_mode = Metrics::kWiFiNetworkPhyMode11a; 405 } 406 407 return phy_mode; 408 } 409 410 // static 411 bool WiFiEndpoint::ParseIEs( 412 const KeyValueStore& properties, 413 Metrics::WiFiNetworkPhyMode* phy_mode, 414 VendorInformation* vendor_information, 415 bool* ieee80211w_required, string* country_code) { 416 417 if (!properties.ContainsUint8s(WPASupplicant::kBSSPropertyIEs)) { 418 SLOG(nullptr, 2) << __func__ << ": No IE property in BSS."; 419 return false; 420 } 421 vector<uint8_t> ies = properties.GetUint8s(WPASupplicant::kBSSPropertyIEs); 422 423 // Format of an information element: 424 // 1 1 1 - 252 425 // +------+--------+----------------+ 426 // | Type | Length | Data | 427 // +------+--------+----------------+ 428 *phy_mode = Metrics::kWiFiNetworkPhyModeUndef; 429 bool found_ht = false; 430 bool found_vht = false; 431 bool found_erp = false; 432 int ie_len = 0; 433 vector<uint8_t>::iterator it; 434 for (it = ies.begin(); 435 std::distance(it, ies.end()) > 1; // Ensure Length field is within PDU. 436 it += ie_len) { 437 ie_len = 2 + *(it + 1); 438 if (std::distance(it, ies.end()) < ie_len) { 439 LOG(ERROR) << __func__ << ": IE extends past containing PDU."; 440 break; 441 } 442 switch (*it) { 443 case IEEE_80211::kElemIdCountry: 444 // Retrieve 2-character country code from the beginning of the element. 445 if (ie_len >= 4) { 446 *country_code = string(it + 2, it + 4); 447 } 448 case IEEE_80211::kElemIdErp: 449 found_erp = true; 450 break; 451 case IEEE_80211::kElemIdHTCap: 452 case IEEE_80211::kElemIdHTInfo: 453 found_ht = true; 454 break; 455 case IEEE_80211::kElemIdVHTCap: 456 case IEEE_80211::kElemIdVHTOperation: 457 found_vht = true; 458 break; 459 case IEEE_80211::kElemIdRSN: 460 ParseWPACapabilities(it + 2, it + ie_len, ieee80211w_required); 461 break; 462 case IEEE_80211::kElemIdVendor: 463 ParseVendorIE(it + 2, it + ie_len, vendor_information, 464 ieee80211w_required); 465 break; 466 } 467 } 468 if (found_vht) { 469 *phy_mode = Metrics::kWiFiNetworkPhyMode11ac; 470 } else if (found_ht) { 471 *phy_mode = Metrics::kWiFiNetworkPhyMode11n; 472 } else if (found_erp) { 473 *phy_mode = Metrics::kWiFiNetworkPhyMode11g; 474 } else { 475 return false; 476 } 477 return true; 478 } 479 480 // static 481 void WiFiEndpoint::ParseWPACapabilities( 482 vector<uint8_t>::const_iterator ie, 483 vector<uint8_t>::const_iterator end, 484 bool* ieee80211w_required) { 485 // Format of an RSN Information Element: 486 // 2 4 487 // +------+--------------------+ 488 // | Type | Group Cipher Suite | 489 // +------+--------------------+ 490 // 2 4 * pairwise count 491 // +-----------------------+---------------------+ 492 // | Pairwise Cipher Count | Pairwise Ciphers... | 493 // +-----------------------+---------------------+ 494 // 2 4 * authkey count 495 // +-----------------------+---------------------+ 496 // | AuthKey Suite Count | AuthKey Suites... | 497 // +-----------------------+---------------------+ 498 // 2 499 // +------------------+ 500 // | RSN Capabilities | 501 // +------------------+ 502 // 2 16 * pmkid count 503 // +------------------+-------------------+ 504 // | PMKID Count | PMKIDs... | 505 // +------------------+-------------------+ 506 // 4 507 // +-------------------------------+ 508 // | Group Management Cipher Suite | 509 // +-------------------------------+ 510 if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountOffset) { 511 return; 512 } 513 ie += IEEE_80211::kRSNIECipherCountOffset; 514 515 // Advance past the pairwise and authkey ciphers. Each is a little-endian 516 // cipher count followed by n * cipher_selector. 517 for (int i = 0; i < IEEE_80211::kRSNIENumCiphers; ++i) { 518 // Retrieve a little-endian cipher count. 519 if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountLen) { 520 return; 521 } 522 uint16_t cipher_count = *ie | (*(ie + 1) << 8); 523 524 // Skip over the cipher selectors. 525 int skip_length = IEEE_80211::kRSNIECipherCountLen + 526 cipher_count * IEEE_80211::kRSNIESelectorLen; 527 if (std::distance(ie, end) < skip_length) { 528 return; 529 } 530 ie += skip_length; 531 } 532 533 if (std::distance(ie, end) < IEEE_80211::kRSNIECapabilitiesLen) { 534 return; 535 } 536 537 // Retrieve a little-endian capabilities bitfield. 538 uint16_t capabilities = *ie | (*(ie + 1) << 8); 539 540 if (capabilities & IEEE_80211::kRSNCapabilityFrameProtectionRequired && 541 ieee80211w_required) { 542 // Never set this value to false, since there may be multiple RSN 543 // information elements. 544 *ieee80211w_required = true; 545 } 546 } 547 548 549 // static 550 void WiFiEndpoint::ParseVendorIE(vector<uint8_t>::const_iterator ie, 551 vector<uint8_t>::const_iterator end, 552 VendorInformation* vendor_information, 553 bool* ieee80211w_required) { 554 // Format of an vendor-specific information element (with type 555 // and length field for the IE removed by the caller): 556 // 3 1 1 - 248 557 // +------------+----------+----------------+ 558 // | OUI | OUI Type | Data | 559 // +------------+----------+----------------+ 560 561 if (std::distance(ie, end) < 4) { 562 LOG(ERROR) << __func__ << ": no room in IE for OUI and type field."; 563 return; 564 } 565 uint32_t oui = (*ie << 16) | (*(ie + 1) << 8) | *(ie + 2); 566 uint8_t oui_type = *(ie + 3); 567 ie += 4; 568 569 if (oui == IEEE_80211::kOUIVendorMicrosoft && 570 oui_type == IEEE_80211::kOUIMicrosoftWPS) { 571 // Format of a WPS data element: 572 // 2 2 573 // +------+--------+----------------+ 574 // | Type | Length | Data | 575 // +------+--------+----------------+ 576 while (std::distance(ie, end) >= 4) { 577 int element_type = (*ie << 8) | *(ie + 1); 578 int element_length = (*(ie + 2) << 8) | *(ie + 3); 579 ie += 4; 580 if (std::distance(ie, end) < element_length) { 581 LOG(ERROR) << __func__ << ": WPS element extends past containing PDU."; 582 break; 583 } 584 string s(ie, ie + element_length); 585 if (base::IsStringASCII(s)) { 586 switch (element_type) { 587 case IEEE_80211::kWPSElementManufacturer: 588 vendor_information->wps_manufacturer = s; 589 break; 590 case IEEE_80211::kWPSElementModelName: 591 vendor_information->wps_model_name = s; 592 break; 593 case IEEE_80211::kWPSElementModelNumber: 594 vendor_information->wps_model_number = s; 595 break; 596 case IEEE_80211::kWPSElementDeviceName: 597 vendor_information->wps_device_name = s; 598 break; 599 } 600 } 601 ie += element_length; 602 } 603 } else if (oui == IEEE_80211::kOUIVendorMicrosoft && 604 oui_type == IEEE_80211::kOUIMicrosoftWPA) { 605 ParseWPACapabilities(ie, end, ieee80211w_required); 606 } else if (oui != IEEE_80211::kOUIVendorEpigram && 607 oui != IEEE_80211::kOUIVendorMicrosoft) { 608 vendor_information->oui_set.insert(oui); 609 } 610 } 611 612 void WiFiEndpoint::CheckForTetheringSignature() { 613 has_tethering_signature_ = 614 Tethering::IsAndroidBSSID(bssid_) || 615 (Tethering::IsLocallyAdministeredBSSID(bssid_) && 616 Tethering::HasIosOui(vendor_information_.oui_set)); 617 } 618 619 } // namespace shill 620