Chromium Code Reviews| 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..224622e9393b27ff686909e668bb21e102ec0fd8 100644 |
| --- a/components/wifi/wifi_service_win.cc |
| +++ b/components/wifi/wifi_service_win.cc |
| @@ -35,9 +35,15 @@ 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"; |
| +const char kProfileImplicitKey[] = "implicit"; |
| + |
| // 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 +68,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 +234,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( |
| @@ -315,6 +334,7 @@ class WiFiServiceImpl : public WiFiService { |
| // 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 +378,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 +395,17 @@ 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); |
| + // Remove profile that was created implicitly or failed to connect. |
| + DWORD RemoveCreatedProfile(const std::string& network_guid, |
| + bool connection_failed); |
| + |
| // Notify |network_list_changed_observer_| that list of visible networks has |
| // changed to |networks|. |
| void NotifyNetworkListChanged(const NetworkList& networks); |
| @@ -390,6 +421,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 +447,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 +475,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 +574,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; |
| } |
| @@ -784,6 +830,36 @@ void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid, |
| if (attempt > kMaxAttempts) { |
| DLOG(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; |
| + } |
| + } |
|
afontan
2014/03/26 17:33:23
We should probably log the case where error_code !
mef
2014/03/26 20:42:30
Done.
|
| + } else { |
| + // Connection has failed, so delete bad created profile. |
| + RemoveCreatedProfile(network_guid, true); |
|
afontan
2014/03/26 17:33:23
Should we check the return value and log if we cou
mef
2014/03/26 20:42:30
Done.
|
| + } |
| + } |
| enable_notify_network_changed_ = true; |
| RestoreNwCategoryWizard(); |
| return; |
| @@ -796,6 +872,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. |
|
afontan
2014/03/26 17:33:23
In this case we are not deleting the profile creat
mef
2014/03/26 20:42:30
Done.
|
| + RemoveCreatedProfile(network_guid, false); |
|
afontan
2014/03/26 17:33:23
We should check the return value and log.
mef
2014/03/26 20:42:30
Done. I've changed it to explicitly remove it from
|
| // Restore previously suppressed notifications. |
| enable_notify_network_changed_ = true; |
| RestoreNwCategoryWizard(); |
| @@ -877,6 +955,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 +997,7 @@ DWORD WiFiServiceImpl::LoadWlanLibrary() { |
| if (!WlanConnect_function_ || |
| !WlanCloseHandle_function_ || |
| + !WlanDeleteProfile_function_ || |
| !WlanDisconnect_function_ || |
| !WlanEnumInterfaces_function_ || |
| !WlanFreeMemory_function_ || |
| @@ -1088,6 +1170,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 +1550,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, |
| @@ -1479,6 +1559,16 @@ DWORD WiFiServiceImpl::Connect(const std::string& network_guid, |
| 0}; |
| error = WlanConnect_function_( |
| client_, &interface_guid_, &wlan_params, NULL); |
| + if (error == ERROR_SUCCESS) { |
| + // Connection in |wlan_connection_mode_discovery_unsecure| mode causes |
| + // system to implicitly create a profile. Mark it as such, and delete in |
| + // |WaitForNetworkConnect| when connection is completed. |
| + scoped_ptr<base::DictionaryValue> implicit_profile( |
| + new base::DictionaryValue()); |
| + implicit_profile->SetBoolean(kProfileImplicitKey, true); |
| + created_profiles_.SetWithoutPathExpansion(network_guid, |
| + implicit_profile.release()); |
| + } |
| } |
| } |
| @@ -1552,14 +1642,58 @@ 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::RemoveCreatedProfile(const std::string& network_guid, |
| + bool connection_failed) { |
| + base::DictionaryValue* created_profile = NULL; |
| + bool implicitly_created = false; |
| + 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)) { |
| + if (connection_failed || |
| + created_profile->GetBoolean(kProfileImplicitKey, &implicitly_created) && |
| + implicitly_created) { |
| + // Connection has failed, or profile was created implicitly, 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; |
| +} |
| + |
| bool WiFiServiceImpl::AuthEncryptionFromSecurity( |
| const std::string& security, |
| + EncryptionType encryption_type, |
| std::string* authentication, |
| std::string* encryption, |
| std::string* key_type) const { |
| @@ -1572,15 +1706,19 @@ 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; |
| + if (encryption_type == kEncryptionTypeTKIP) { |
| + *encryption = kEncryptionTKIP; |
| + } else { |
| + *encryption = kEncryptionAES; |
| + } |
| *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; |
| + if (encryption_type == kEncryptionTypeTKIP) { |
| + *encryption = kEncryptionTKIP; |
| + } else { |
| + *encryption = kEncryptionAES; |
| + } |
| *key_type = kKeyTypePassphrase; |
|
afontan
2014/03/26 17:33:23
This if/else is getting a bit long so is harder to
mef
2014/03/26 20:42:30
I've added a helper method. A switch doesn't work
|
| } else { |
| return false; |
| @@ -1590,12 +1728,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); |