Index: chrome/utility/wifi/wifi_service_win.cc |
diff --git a/chrome/utility/wifi/wifi_service_win.cc b/chrome/utility/wifi/wifi_service_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e10170f8717c14c56890611d1ac2df9e2e31ac77 |
--- /dev/null |
+++ b/chrome/utility/wifi/wifi_service_win.cc |
@@ -0,0 +1,394 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/utility/wifi/wifi_service.h" |
+ |
+#include <wlanapi.h> |
+#pragma comment(lib, "Wlanapi.lib") |
+ |
+#include "base/message_loop/message_loop.h" |
+#include "base/strings/string16.h" |
+#include "base/strings/utf_string_conversions.h" |
+ |
+class WiFiServiceImpl : public WiFiService { |
+ public: |
+ WiFiServiceImpl() : client_(NULL) {} |
+ |
+ virtual ~WiFiServiceImpl() { CloseClientHandle(); } |
+ |
+ virtual void GetProperties(const std::string& network_guid, |
+ const NetworkPropertiesCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ DWORD error = OpenClientHandle(); |
+ |
+ if (error == ERROR_SUCCESS) { |
+ NetworkList network_list; |
+ error = GetVisibleNetworkList(&network_list); |
+ if (error == ERROR_SUCCESS && !network_list.empty()) { |
+ NetworkList::iterator it = FindNetwork(network_list, network_guid); |
+ if (it != network_list.end()) |
+ callback.Run(network_guid, *it); |
+ else |
+ error = ERROR_NOT_FOUND; |
+ } |
+ } |
+ |
+ CheckError(error_callback, "Error.DBusFailed", error); |
+ } |
+ |
+ virtual void GetState(const std::string& network_guid, |
+ const NetworkPropertiesCallback& callback, |
+ const ErrorCallback& error_callback) OVERRIDE {} |
+ |
+ virtual void GetManagedProperties( |
+ const std::string& network_guid, |
+ const DictionaryResultCallback& callback, |
+ const ErrorCallback& error_callback) OVERRIDE {} |
+ |
+ virtual void SetProperties(const std::string& network_guid, |
+ const base::DictionaryValue& properties, |
+ const StringResultCallback& callback, |
+ const ErrorCallback& error_callback) OVERRIDE {} |
+ |
+ virtual void GetVisibleNetworks( |
+ const NetworkListCallback& callback, |
+ const ErrorCallback& error_callback) OVERRIDE { |
+ DWORD error = OpenClientHandle(); |
+ |
+ if (error == ERROR_SUCCESS) { |
+ NetworkList network_list; |
+ error = GetVisibleNetworkList(&network_list); |
+ if (error == ERROR_SUCCESS && !network_list.empty()) { |
+ SortNetworks(network_list); |
+ callback.Run(network_list); |
+ } |
+ } |
+ |
+ CheckError(error_callback, "Error.DBusFailed", error); |
+ } |
+ |
+ virtual void RequestNetworkScan() OVERRIDE {} |
+ |
+ virtual void StartConnect(const std::string& network_guid, |
+ const StringResultCallback& callback, |
+ const ErrorCallback& error_callback) OVERRIDE { |
+ DWORD error = OpenClientHandle(); |
+ |
+ if (error == ERROR_SUCCESS) { |
+ error = Connect(network_guid); |
+ if (error == ERROR_SUCCESS) { |
+ callback.Run(network_guid); |
+ } |
+ } |
+ |
+ CheckError(error_callback, "Error.DBusFailed", error); |
+ } |
+ |
+ virtual void StartDisconnect(const std::string& network_guid, |
+ const StringResultCallback& callback, |
+ const ErrorCallback& error_callback) OVERRIDE { |
+ DWORD error = OpenClientHandle(); |
+ |
+ if (error == ERROR_SUCCESS) { |
+ SaveTempProfile(network_guid); |
+ |
+ std::string profile_xml; |
+ error = GetProfile(network_guid, &profile_xml); |
+ if (error == ERROR_SUCCESS) { |
+ error = Disconnect(); |
+ if (error == ERROR_SUCCESS) { |
+ callback.Run(network_guid); |
+ } |
+ } |
+ } |
+ |
+ CheckError(error_callback, "Error.DBusFailed", error); |
+ } |
+ |
+ private: |
+ bool CheckError(const ErrorCallback& error_callback, |
+ const std::string& error_name, |
+ DWORD error_code) { |
+ if (error_code != ERROR_SUCCESS) { |
+ scoped_ptr<base::DictionaryValue> error_data(new base::DictionaryValue); |
+ error_data->SetInteger("Win32ErrorCode", error_code); |
+ error_callback.Run(error_name, error_data.Pass()); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ NetworkList::iterator FindNetwork(NetworkList& networks, |
+ const std::string& network_guid) { |
+ for (NetworkList::iterator it = networks.begin(); it != networks.end(); |
+ ++it) { |
+ if (it->guid == network_guid) |
+ return it; |
+ } |
+ return networks.end(); |
+ } |
+ |
+ void SortNetworks(NetworkList& networks) { |
+ // Sort networks, so connected/connecting is up front, then by type: |
+ // Ethernet, WiFi, Cellular, VPN |
+ networks.sort(WiFiService::NetworkProperties::OrderByType); |
+ } |
+ |
+ // open a WLAN client handle |
+ DWORD OpenClientHandle() { |
+ CloseClientHandle(); |
+ |
+ DWORD error = ERROR_SUCCESS; |
+ DWORD service_version = 0; |
+ |
+ // open a handle to the service |
+ error = WlanOpenHandle(WLAN_API_VERSION, NULL, &service_version, &client_); |
+ |
+ PWLAN_INTERFACE_INFO_LIST pIntfList = NULL; |
+ UINT i = 0; |
+ |
+ if (error == ERROR_SUCCESS) { |
+ // enumerate wireless interfaces |
+ error = WlanEnumInterfaces(client_, NULL, &pIntfList); |
+ if (error == ERROR_SUCCESS) { |
+ if (pIntfList != NULL && pIntfList->dwNumberOfItems != 0) { |
+ // Use first interface. |
+ interface_guid_ = pIntfList->InterfaceInfo[0].InterfaceGuid; |
+ } else { |
+ error = ERROR_NOINTERFACE; |
+ } |
+ } |
+ // clean up |
+ if (pIntfList != NULL) |
+ WlanFreeMemory(pIntfList); |
+ } |
+ |
+ return error; |
+ } |
+ |
+ DWORD CloseClientHandle() { |
+ DWORD error = ERROR_SUCCESS; |
+ if (client_ != NULL) { |
+ WlanCloseHandle(client_, NULL); |
+ client_ = NULL; |
+ } |
+ return error; |
+ } |
+ |
+ |
+ base::string16 ProfileNameFromGuid(const std::string& network_guid) const { |
+ return base::UTF8ToUTF16(network_guid); |
+ } |
+ |
+ DOT11_SSID SsidFromGuid(const std::string& network_guid) const { |
+ DOT11_SSID ssid = {0}; |
+ if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) { |
+ ssid.uSSIDLength = network_guid.length(); |
+ strncpy(reinterpret_cast<char*>(ssid.ucSSID), |
+ network_guid.c_str(), |
+ ssid.uSSIDLength); |
+ } |
+ return ssid; |
+ } |
+ |
+ std::string GuidFromProfileAndSsid(const std::string& profile_name, |
+ const std::string& ssid) { |
+ return ssid; |
+ } |
+ |
+ WiFiService::Security SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) { |
+ // TODO(mef): Figure out correct mapping. |
+ switch(alg) { |
+ case DOT11_AUTH_ALGO_RSNA: |
+ return kSecurityWPA; |
+ case DOT11_AUTH_ALGO_RSNA_PSK: |
+ return kSecurityWPA_PSK; |
+ case DOT11_AUTH_ALGO_80211_SHARED_KEY: |
+ return kSecurityWEP_PSK; |
+ case DOT11_AUTH_ALGO_80211_OPEN: |
+ return kSecurityNone; |
+ default: |
+ return kSecurityUnknown; |
+ } |
+ return kSecurityUnknown; |
+ } |
+ |
+ void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan, |
+ const WLAN_BSS_LIST& wlan_bss_list, |
+ NetworkProperties* properties) { |
+ if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { |
+ properties->connection_state = WiFiService::kConnectionStateConnected; |
+ } else { |
+ properties->connection_state = WiFiService::kConnectionStateNotConnected; |
+ } |
+ |
+ properties->ssid = |
+ std::string(reinterpret_cast<const char*>(wlan.dot11Ssid.ucSSID), |
+ wlan.dot11Ssid.uSSIDLength); |
+ properties->name = properties->ssid; |
+ properties->guid = GuidFromProfileAndSsid(properties->name, |
+ properties->ssid); |
+ properties->type = WiFiService::kNetworkTypeWiFi; |
+ |
+ for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) { |
+ const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]); |
+ if (bss_entry.dot11Ssid.uSSIDLength == wlan.dot11Ssid.uSSIDLength |
+ && 0 == memcmp(bss_entry.dot11Ssid.ucSSID, wlan.dot11Ssid.ucSSID, |
+ bss_entry.dot11Ssid.uSSIDLength)) { |
+ if (bss_entry.ulChCenterFrequency < 3000000) |
+ properties->frequency = kFrequency2400; |
+ else |
+ properties->frequency = kFrequency5000; |
+ properties->frequency_list.push_back(properties->frequency); |
+ properties->bssid = |
+ WiFiService::NetworkProperties::MacAddressAsString( |
+ bss_entry.dot11Bssid); |
+ } |
+ } |
+ properties->frequency_list.sort(); |
+ properties->frequency_list.unique(); |
+ |
+ properties->security = |
+ SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm); |
+ |
+ properties->signal_strength = wlan.wlanSignalQuality; |
+ } |
+ |
+ // get the list of visible wireless networks |
+ DWORD GetVisibleNetworkList(NetworkList* network_list) { |
+ DWORD error = ERROR_SUCCESS; |
+ |
+ if (client_ == NULL) { |
+ return ERROR_NOINTERFACE; |
+ } |
+ |
+ PWLAN_AVAILABLE_NETWORK_LIST pVList = NULL; |
+ PWLAN_BSS_LIST pWlanBssList = NULL; |
+ |
+ error = WlanGetAvailableNetworkList( |
+ client_, &interface_guid_, 0, NULL, &pVList); |
+ |
+ if (error == ERROR_SUCCESS && NULL != pVList) { |
+ error = WlanGetNetworkBssList( |
+ client_, &interface_guid_, NULL, dot11_BSS_type_any, FALSE, NULL, |
+ &pWlanBssList); |
+ if (error == ERROR_SUCCESS && NULL != pWlanBssList) { |
+ for (DWORD i = 0; i < pVList->dwNumberOfItems; ++i) { |
+ network_list->push_back(NetworkProperties()); |
+ NetworkPropertiesFromAvailableNetwork(pVList->Network[i], |
+ *pWlanBssList, |
+ &network_list->back()); |
+ } |
+ } |
+ } |
+ |
+ // clean up |
+ if (pVList != NULL) { |
+ WlanFreeMemory(pVList); |
+ } |
+ if (pWlanBssList != NULL) { |
+ WlanFreeMemory(pWlanBssList); |
+ } |
+ |
+ return error; |
+ } |
+ |
+ DWORD Connect(const std::string& network_guid) { |
+ DWORD error = ERROR_SUCCESS; |
+ |
+ if (client_ == NULL) { |
+ return ERROR_NOINTERFACE; |
+ } |
+ |
+ base::string16 profile_name = ProfileNameFromGuid(network_guid); |
+ |
+ if(HaveProfile(network_guid)) { |
+ WLAN_CONNECTION_PARAMETERS wlan_params = {wlan_connection_mode_profile, |
+ profile_name.c_str(), |
+ NULL, |
+ NULL, |
+ dot11_BSS_type_any, |
+ 0 |
+ }; |
+ error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); |
+ } else { |
+ DOT11_SSID ssid = SsidFromGuid(network_guid); |
+ WLAN_CONNECTION_PARAMETERS wlan_params = { |
+ wlan_connection_mode_discovery_unsecure, |
+ NULL, |
+ &ssid, |
+ NULL, |
+ dot11_BSS_type_infrastructure, |
+ 0 |
+ }; |
+ error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); |
+ } |
+ |
+ return error; |
+ } |
+ |
+ DWORD Disconnect() { |
+ DWORD error = ERROR_SUCCESS; |
+ |
+ if (client_ == NULL) { |
+ return ERROR_NOINTERFACE; |
+ } |
+ |
+ error = ::WlanDisconnect(client_, &interface_guid_, NULL); |
+ return error; |
+ } |
+ |
+ DWORD SaveTempProfile(const std::string& network_guid) { |
+ DWORD error = ERROR_SUCCESS; |
+ |
+ if (client_ == NULL) { |
+ return ERROR_NOINTERFACE; |
+ } |
+ |
+ base::string16 profile_name = ProfileNameFromGuid(network_guid); |
+ |
+ error = ::WlanSaveTemporaryProfile(client_, &interface_guid_, |
+ profile_name.c_str(), NULL, 0, true, NULL); |
+ return error; |
+ } |
+ |
+ DWORD GetProfile(const std::string& network_guid, |
+ std::string* profile_xml) { |
+ DWORD error = ERROR_SUCCESS; |
+ |
+ if (client_ == NULL) { |
+ return ERROR_NOINTERFACE; |
+ } |
+ |
+ base::string16 profile_name = ProfileNameFromGuid(network_guid); |
+ LPWSTR str_profile_xml = NULL; |
+ error = ::WlanGetProfile(client_, &interface_guid_, |
+ profile_name.c_str(), NULL, &str_profile_xml, NULL, NULL); |
+ |
+ if (error == ERROR_SUCCESS && str_profile_xml != NULL) { |
+ *profile_xml = base::UTF16ToUTF8(str_profile_xml); |
+ } |
+ // clean up |
+ if (str_profile_xml != NULL) { |
+ WlanFreeMemory(str_profile_xml); |
+ } |
+ |
+ return error; |
+ } |
+ |
+ bool HaveProfile(const std::string& network_guid) { |
+ DWORD error = ERROR_SUCCESS; |
+ std::string profile_xml; |
+ return GetProfile(network_guid, &profile_xml) == ERROR_SUCCESS; |
+ } |
+ |
+ // Wlan Service Handle. |
+ HANDLE client_; |
+ // Wlan Interface Guid. |
+ GUID interface_guid_; |
+ |
+}; |
+ |
+WiFiService* WiFiService::CreateService() { return new WiFiServiceImpl(); } |
+ |