| Index: components/wifi/wifi_service_win.cc
|
| diff --git a/components/wifi/wifi_service_win.cc b/components/wifi/wifi_service_win.cc
|
| index 1280b4944ec666593db09375b87ffb98890820c7..6afc8723851b8d68f7a44a9754922502890fdad3 100644
|
| --- a/components/wifi/wifi_service_win.cc
|
| +++ b/components/wifi/wifi_service_win.cc
|
| @@ -35,9 +35,14 @@ const wchar_t kNwCategoryWizardSavedRegValue[] = L"ShowSaved";
|
| const wchar_t kNwCategoryWizardDeleteRegValue[] = L"ShowDelete";
|
| const wchar_t kWlanApiDll[] = L"wlanapi.dll";
|
|
|
| +// Created Profile Dictionary keys
|
| +const char kProfileXmlKey[] = "xml";
|
| +const char kProfileSharedKey[] = "shared";
|
| +
|
| // WlanApi function names
|
| const char kWlanConnect[] = "WlanConnect";
|
| const char kWlanCloseHandle[] = "WlanCloseHandle";
|
| +const char kWlanDeleteProfile[] = "WlanDeleteProfile";
|
| const char kWlanDisconnect[] = "WlanDisconnect";
|
| const char kWlanEnumInterfaces[] = "WlanEnumInterfaces";
|
| const char kWlanFreeMemory[] = "WlanFreeMemory";
|
| @@ -62,6 +67,12 @@ typedef DWORD (WINAPI* WlanCloseHandleFunction)(
|
| HANDLE hClientHandle,
|
| PVOID pReserved);
|
|
|
| +typedef DWORD (WINAPI* WlanDeleteProfileFunction)(
|
| + HANDLE hClientHandle,
|
| + const GUID *pInterfaceGuid,
|
| + LPCWSTR strProfileName,
|
| + PVOID pReserved);
|
| +
|
| typedef DWORD (WINAPI* WlanDisconnectFunction)(
|
| HANDLE hClientHandle,
|
| CONST GUID *pInterfaceGuid,
|
| @@ -222,6 +233,13 @@ class WiFiServiceImpl : public WiFiService {
|
| virtual void RequestConnectedNetworkUpdate() OVERRIDE {}
|
|
|
| private:
|
| + typedef int32 EncryptionType;
|
| + enum EncryptionTypeEnum {
|
| + kEncryptionTypeAny = 0,
|
| + kEncryptionTypeAES = 1,
|
| + kEncryptionTypeTKIP = 2
|
| + };
|
| +
|
| // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification
|
| // on WiFiServiceImpl passed back as |context|.
|
| static void __stdcall OnWlanNotificationCallback(
|
| @@ -313,8 +331,13 @@ class WiFiServiceImpl : public WiFiService {
|
| // Deduce |onc::wifi| security from |alg|.
|
| std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const;
|
|
|
| + // Convert |EncryptionType| into WPA(2) encryption type string.
|
| + std::string WpaEncryptionFromEncryptionType(
|
| + EncryptionType encryption_type) const;
|
| +
|
| // Deduce WLANProfile |authEncryption| values from |onc::wifi| security.
|
| bool AuthEncryptionFromSecurity(const std::string& security,
|
| + EncryptionType encryption_type,
|
| std::string* authentication,
|
| std::string* encryption,
|
| std::string* key_type) const;
|
| @@ -358,8 +381,11 @@ class WiFiServiceImpl : public WiFiService {
|
| // Normalizes |frequency_in_mhz| into one of |Frequency| values.
|
| Frequency GetNormalizedFrequency(int frequency_in_mhz) const;
|
|
|
| - // Create |profile_xml| based on |network_properties|.
|
| + // Create |profile_xml| based on |network_properties|. If |encryption_type|
|
| + // is |kEncryptionTypeAny| applies the type most suitable for parameters in
|
| + // |network_properties|.
|
| bool CreateProfile(const NetworkProperties& network_properties,
|
| + EncryptionType encryption_type,
|
| std::string* profile_xml);
|
|
|
| // Save temporary wireless profile for |network_guid|.
|
| @@ -372,9 +398,16 @@ class WiFiServiceImpl : public WiFiService {
|
| bool get_plaintext_key,
|
| std::string* profile_xml);
|
|
|
| + // Set |profile_xml| to current user or all users depending on |shared| flag.
|
| + // If |overwrite| is false, then returns an error if profile exists.
|
| + DWORD SetProfile(bool shared, const std::string& profile_xml, bool overwrite);
|
| +
|
| // Return true if there is previously stored profile xml for |network_guid|.
|
| bool HaveProfile(const std::string& network_guid);
|
|
|
| + // Delete profile that was created, but failed to connect.
|
| + DWORD DeleteCreatedProfile(const std::string& network_guid);
|
| +
|
| // Notify |network_list_changed_observer_| that list of visible networks has
|
| // changed to |networks|.
|
| void NotifyNetworkListChanged(const NetworkList& networks);
|
| @@ -390,6 +423,7 @@ class WiFiServiceImpl : public WiFiService {
|
| // WlanApi function pointers
|
| WlanConnectFunction WlanConnect_function_;
|
| WlanCloseHandleFunction WlanCloseHandle_function_;
|
| + WlanDeleteProfileFunction WlanDeleteProfile_function_;
|
| WlanDisconnectFunction WlanDisconnect_function_;
|
| WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
|
| WlanFreeMemoryFunction WlanFreeMemory_function_;
|
| @@ -415,6 +449,11 @@ class WiFiServiceImpl : public WiFiService {
|
| base::DictionaryValue connect_properties_;
|
| // Preserved WLAN profile xml.
|
| std::map<std::string, std::string> saved_profiles_xml_;
|
| + // Created WLAN Profiles, indexed by |network_guid|. Contains xml with TKIP
|
| + // encryption type saved by |CreateNetwork| if applicable. Profile has to be
|
| + // deleted if connection fails. Implicitly created profiles have to be deleted
|
| + // if connection succeeds. Persist only in memory.
|
| + base::DictionaryValue created_profiles_;
|
| // Observer to get notified when network(s) have changed (e.g. connect).
|
| NetworkGuidListCallback networks_changed_observer_;
|
| // Observer to get notified when network list has changed (scan complete).
|
| @@ -438,6 +477,7 @@ WiFiServiceImpl::WiFiServiceImpl()
|
| : wlan_api_library_(NULL),
|
| WlanConnect_function_(NULL),
|
| WlanCloseHandle_function_(NULL),
|
| + WlanDeleteProfile_function_(NULL),
|
| WlanDisconnect_function_(NULL),
|
| WlanEnumInterfaces_function_(NULL),
|
| WlanFreeMemory_function_(NULL),
|
| @@ -536,28 +576,36 @@ void WiFiServiceImpl::CreateNetwork(
|
|
|
| network_properties.guid = network_properties.ssid;
|
| std::string profile_xml;
|
| - if (!CreateProfile(network_properties, &profile_xml)) {
|
| + if (!CreateProfile(network_properties, kEncryptionTypeAny, &profile_xml)) {
|
| CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error);
|
| return;
|
| }
|
|
|
| - base::string16 profile_xml16(base::UTF8ToUTF16(profile_xml));
|
| - DWORD reason_code = 0u;
|
| -
|
| - error_code = WlanSetProfile_function_(client_,
|
| - &interface_guid_,
|
| - shared ? 0 : WLAN_PROFILE_USER,
|
| - profile_xml16.c_str(),
|
| - NULL,
|
| - FALSE,
|
| - NULL,
|
| - &reason_code);
|
| + error_code = SetProfile(shared, profile_xml, false);
|
| if (CheckError(error_code, kWiFiServiceError, error)) {
|
| DVLOG(0) << profile_xml;
|
| - DVLOG(0) << "SetProfile Reason Code:" << reason_code;
|
| return;
|
| }
|
|
|
| + // WAP and WAP2 networks could use either AES or TKIP encryption type.
|
| + // Preserve alternative profile to use in case if connection with default
|
| + // encryption type fails.
|
| + std::string tkip_profile_xml;
|
| + if (!CreateProfile(network_properties,
|
| + kEncryptionTypeTKIP,
|
| + &tkip_profile_xml)) {
|
| + CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error);
|
| + return;
|
| + }
|
| +
|
| + if (tkip_profile_xml != profile_xml) {
|
| + scoped_ptr<base::DictionaryValue> tkip_profile(new base::DictionaryValue());
|
| + tkip_profile->SetString(kProfileXmlKey, tkip_profile_xml);
|
| + tkip_profile->SetBoolean(kProfileSharedKey, shared);
|
| + created_profiles_.SetWithoutPathExpansion(network_properties.guid,
|
| + tkip_profile.release());
|
| + }
|
| +
|
| *network_guid = network_properties.guid;
|
| }
|
|
|
| @@ -779,11 +827,49 @@ void WiFiServiceImpl::OnNetworkScanCompleteOnMainThread() {
|
|
|
| void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid,
|
| int attempt) {
|
| - // If network didn't get connected in |kMaxAttempts|, then restore automatic
|
| - // network change notifications and stop waiting.
|
| + // If network didn't get connected in |kMaxAttempts|, then try to connect
|
| + // using different profile if it was created recently.
|
| if (attempt > kMaxAttempts) {
|
| - DLOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to "
|
| - << network_guid;
|
| + LOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to "
|
| + << network_guid;
|
| +
|
| + base::DictionaryValue* created_profile = NULL;
|
| + // Check, whether this connection is using newly created profile.
|
| + if (created_profiles_.GetDictionaryWithoutPathExpansion(
|
| + network_guid, &created_profile)) {
|
| + std::string tkip_profile_xml;
|
| + bool shared = false;
|
| + // Check, if this connection there is alternative TKIP profile xml that
|
| + // should be tried. If there is, then set it up and try to connect again.
|
| + if (created_profile->GetString(kProfileXmlKey, &tkip_profile_xml) &&
|
| + created_profile->GetBoolean(kProfileSharedKey, &shared)) {
|
| + // Remove TKIP profile xml, so it will not be tried again.
|
| + created_profile->Remove(kProfileXmlKey, NULL);
|
| + created_profile->Remove(kProfileSharedKey, NULL);
|
| + DWORD error_code = SetProfile(shared, tkip_profile_xml, true);
|
| + if (error_code == ERROR_SUCCESS) {
|
| + // Try to connect with new profile.
|
| + error_code = Connect(network_guid,
|
| + GetFrequencyToConnect(network_guid));
|
| + if (error_code == ERROR_SUCCESS) {
|
| + // Start waiting again.
|
| + WaitForNetworkConnect(network_guid, 0);
|
| + return;
|
| + } else {
|
| + LOG(ERROR) << "Failed to set created profile for " << network_guid
|
| + << " error=" << error_code;
|
| + }
|
| + }
|
| + } else {
|
| + // Connection has failed, so delete bad created profile.
|
| + DWORD error_code = DeleteCreatedProfile(network_guid);
|
| + if (error_code != ERROR_SUCCESS) {
|
| + LOG(ERROR) << "Failed to delete created profile for " << network_guid
|
| + << " error=" << error_code;
|
| + }
|
| + }
|
| + }
|
| + // Restore automatic network change notifications and stop waiting.
|
| enable_notify_network_changed_ = true;
|
| RestoreNwCategoryWizard();
|
| return;
|
| @@ -796,6 +882,8 @@ void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid,
|
| // e.g. after Chromecast device reset. Reset DHCP on wireless network to
|
| // work around this issue.
|
| error = ResetDHCP();
|
| + // There is no need to keep created profile as network is connected.
|
| + created_profiles_.RemoveWithoutPathExpansion(network_guid, NULL);
|
| // Restore previously suppressed notifications.
|
| enable_notify_network_changed_ = true;
|
| RestoreNwCategoryWizard();
|
| @@ -877,6 +965,9 @@ DWORD WiFiServiceImpl::LoadWlanLibrary() {
|
| WlanCloseHandle_function_ =
|
| reinterpret_cast<WlanCloseHandleFunction>(
|
| ::GetProcAddress(wlan_api_library_, kWlanCloseHandle));
|
| + WlanDeleteProfile_function_ =
|
| + reinterpret_cast<WlanDeleteProfileFunction>(
|
| + ::GetProcAddress(wlan_api_library_, kWlanDeleteProfile));
|
| WlanDisconnect_function_ =
|
| reinterpret_cast<WlanDisconnectFunction>(
|
| ::GetProcAddress(wlan_api_library_, kWlanDisconnect));
|
| @@ -916,6 +1007,7 @@ DWORD WiFiServiceImpl::LoadWlanLibrary() {
|
|
|
| if (!WlanConnect_function_ ||
|
| !WlanCloseHandle_function_ ||
|
| + !WlanDeleteProfile_function_ ||
|
| !WlanDisconnect_function_ ||
|
| !WlanEnumInterfaces_function_ ||
|
| !WlanFreeMemory_function_ ||
|
| @@ -1088,6 +1180,7 @@ DWORD WiFiServiceImpl::CloseClientHandle() {
|
| if (wlan_api_library_ != NULL) {
|
| WlanConnect_function_ = NULL;
|
| WlanCloseHandle_function_ = NULL;
|
| + WlanDeleteProfile_function_ = NULL;
|
| WlanDisconnect_function_ = NULL;
|
| WlanEnumInterfaces_function_ = NULL;
|
| WlanFreeMemory_function_ = NULL;
|
| @@ -1467,9 +1560,6 @@ DWORD WiFiServiceImpl::Connect(const std::string& network_guid,
|
| error = WlanConnect_function_(
|
| client_, &interface_guid_, &wlan_params, NULL);
|
| } else {
|
| - // TODO(mef): wlan_connection_mode_discovery_unsecure is not available on
|
| - // XP. If XP support is needed, then temporary profile will have to be
|
| - // created.
|
| WLAN_CONNECTION_PARAMETERS wlan_params = {
|
| wlan_connection_mode_discovery_unsecure,
|
| NULL,
|
| @@ -1552,14 +1642,59 @@ DWORD WiFiServiceImpl::GetProfile(const std::string& network_guid,
|
| return error;
|
| }
|
|
|
| +DWORD WiFiServiceImpl::SetProfile(bool shared,
|
| + const std::string& profile_xml,
|
| + bool overwrite) {
|
| + DWORD error_code = ERROR_SUCCESS;
|
| +
|
| + base::string16 profile_xml16(base::UTF8ToUTF16(profile_xml));
|
| + DWORD reason_code = 0u;
|
| +
|
| + error_code = WlanSetProfile_function_(client_,
|
| + &interface_guid_,
|
| + shared ? 0 : WLAN_PROFILE_USER,
|
| + profile_xml16.c_str(),
|
| + NULL,
|
| + overwrite,
|
| + NULL,
|
| + &reason_code);
|
| + return error_code;
|
| +}
|
| +
|
| bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) {
|
| DWORD error = ERROR_SUCCESS;
|
| std::string profile_xml;
|
| return GetProfile(network_guid, false, &profile_xml) == ERROR_SUCCESS;
|
| }
|
|
|
| +
|
| +DWORD WiFiServiceImpl::DeleteCreatedProfile(const std::string& network_guid) {
|
| + base::DictionaryValue* created_profile = NULL;
|
| + DWORD error_code = ERROR_SUCCESS;
|
| + // Check, whether this connection is using new created profile, and remove it.
|
| + if (created_profiles_.GetDictionaryWithoutPathExpansion(
|
| + network_guid, &created_profile)) {
|
| + // Connection has failed, so delete it.
|
| + base::string16 profile_name = ProfileNameFromGUID(network_guid);
|
| + error_code = WlanDeleteProfile_function_(client_,
|
| + &interface_guid_,
|
| + profile_name.c_str(),
|
| + NULL);
|
| + created_profiles_.RemoveWithoutPathExpansion(network_guid, NULL);
|
| + }
|
| + return error_code;
|
| +}
|
| +
|
| +std::string WiFiServiceImpl::WpaEncryptionFromEncryptionType(
|
| + EncryptionType encryption_type) const {
|
| + if (encryption_type == kEncryptionTypeTKIP)
|
| + return kEncryptionTKIP;
|
| + return kEncryptionAES;
|
| +}
|
| +
|
| bool WiFiServiceImpl::AuthEncryptionFromSecurity(
|
| const std::string& security,
|
| + EncryptionType encryption_type,
|
| std::string* authentication,
|
| std::string* encryption,
|
| std::string* key_type) const {
|
| @@ -1572,15 +1707,11 @@ bool WiFiServiceImpl::AuthEncryptionFromSecurity(
|
| *key_type = kKeyTypeNetwork;
|
| } else if (security == onc::wifi::kWPA_PSK) {
|
| *authentication = kAuthenticationWpaPsk;
|
| - // TODO(mef): WAP |encryption| could be either |AES| or |TKIP|. It has to be
|
| - // determined and adjusted properly during |Connect|.
|
| - *encryption = kEncryptionAES;
|
| + *encryption = WpaEncryptionFromEncryptionType(encryption_type);
|
| *key_type = kKeyTypePassphrase;
|
| } else if (security == onc::wifi::kWPA2_PSK) {
|
| *authentication = kAuthenticationWpa2Psk;
|
| - // TODO(mef): WAP |encryption| could be either |AES| or |TKIP|. It has to be
|
| - // determined and adjusted properly during |Connect|.
|
| - *encryption = kEncryptionAES;
|
| + *encryption = WpaEncryptionFromEncryptionType(encryption_type);
|
| *key_type = kKeyTypePassphrase;
|
| } else {
|
| return false;
|
| @@ -1590,12 +1721,14 @@ bool WiFiServiceImpl::AuthEncryptionFromSecurity(
|
|
|
| bool WiFiServiceImpl::CreateProfile(
|
| const NetworkProperties& network_properties,
|
| + EncryptionType encryption_type,
|
| std::string* profile_xml) {
|
| // Get authentication and encryption values from security.
|
| std::string authentication;
|
| std::string encryption;
|
| std::string key_type;
|
| bool valid = AuthEncryptionFromSecurity(network_properties.security,
|
| + encryption_type,
|
| &authentication,
|
| &encryption,
|
| &key_type);
|
|
|