Home | History | Annotate | Download | only in wifi
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/wifi/wifi_service.h"
      6 
      7 #include <iphlpapi.h>
      8 #include <objbase.h>
      9 #include <wlanapi.h>
     10 
     11 #include <set>
     12 
     13 #include "base/base_paths_win.h"
     14 #include "base/bind.h"
     15 #include "base/files/file_path.h"
     16 #include "base/memory/ref_counted.h"
     17 #include "base/message_loop/message_loop.h"
     18 #include "base/path_service.h"
     19 #include "base/strings/string16.h"
     20 #include "base/strings/string_util.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "base/win/registry.h"
     23 #include "components/onc/onc_constants.h"
     24 #include "components/wifi/network_properties.h"
     25 #include "third_party/libxml/chromium/libxml_utils.h"
     26 
     27 namespace {
     28 const wchar_t kNwCategoryWizardRegKey[] =
     29     L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Network\\"
     30     L"NwCategoryWizard";
     31 const wchar_t kNwCategoryWizardRegValue[] = L"Show";
     32 const wchar_t kNwCategoryWizardSavedRegValue[] = L"ShowSaved";
     33 const wchar_t kNwCategoryWizardDeleteRegValue[] = L"ShowDelete";
     34 const wchar_t kWlanApiDll[] = L"wlanapi.dll";
     35 
     36 // Created Profile Dictionary keys
     37 const char kProfileXmlKey[] = "xml";
     38 const char kProfileSharedKey[] = "shared";
     39 
     40 // WlanApi function names
     41 const char kWlanConnect[] = "WlanConnect";
     42 const char kWlanCloseHandle[] = "WlanCloseHandle";
     43 const char kWlanDeleteProfile[] = "WlanDeleteProfile";
     44 const char kWlanDisconnect[] = "WlanDisconnect";
     45 const char kWlanEnumInterfaces[] = "WlanEnumInterfaces";
     46 const char kWlanFreeMemory[] = "WlanFreeMemory";
     47 const char kWlanGetAvailableNetworkList[] = "WlanGetAvailableNetworkList";
     48 const char kWlanGetNetworkBssList[] = "WlanGetNetworkBssList";
     49 const char kWlanGetProfile[] = "WlanGetProfile";
     50 const char kWlanOpenHandle[] = "WlanOpenHandle";
     51 const char kWlanQueryInterface[] = "WlanQueryInterface";
     52 const char kWlanRegisterNotification[] = "WlanRegisterNotification";
     53 const char kWlanSaveTemporaryProfile[] = "WlanSaveTemporaryProfile";
     54 const char kWlanScan[] = "WlanScan";
     55 const char kWlanSetProfile[] = "WlanSetProfile";
     56 
     57 // WlanApi function definitions
     58 typedef DWORD(WINAPI* WlanConnectFunction)(
     59     HANDLE hClientHandle,
     60     CONST GUID* pInterfaceGuid,
     61     CONST PWLAN_CONNECTION_PARAMETERS pConnectionParameters,
     62     PVOID pReserved);
     63 
     64 typedef DWORD (WINAPI* WlanCloseHandleFunction)(
     65     HANDLE hClientHandle,
     66     PVOID pReserved);
     67 
     68 typedef DWORD(WINAPI* WlanDeleteProfileFunction)(HANDLE hClientHandle,
     69                                                  const GUID* pInterfaceGuid,
     70                                                  LPCWSTR strProfileName,
     71                                                  PVOID pReserved);
     72 
     73 typedef DWORD(WINAPI* WlanDisconnectFunction)(HANDLE hClientHandle,
     74                                               CONST GUID* pInterfaceGuid,
     75                                               PVOID pReserved);
     76 
     77 typedef DWORD(WINAPI* WlanEnumInterfacesFunction)(
     78     HANDLE hClientHandle,
     79     PVOID pReserved,
     80     PWLAN_INTERFACE_INFO_LIST* ppInterfaceList);
     81 
     82 typedef VOID (WINAPI* WlanFreeMemoryFunction)(
     83     _In_ PVOID pMemory);
     84 
     85 typedef DWORD(WINAPI* WlanGetAvailableNetworkListFunction)(
     86     HANDLE hClientHandle,
     87     CONST GUID* pInterfaceGuid,
     88     DWORD dwFlags,
     89     PVOID pReserved,
     90     PWLAN_AVAILABLE_NETWORK_LIST* ppAvailableNetworkList);
     91 
     92 typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)(
     93     HANDLE hClientHandle,
     94     const GUID* pInterfaceGuid,
     95     const  PDOT11_SSID pDot11Ssid,
     96     DOT11_BSS_TYPE dot11BssType,
     97     BOOL bSecurityEnabled,
     98     PVOID pReserved,
     99     PWLAN_BSS_LIST* ppWlanBssList);
    100 
    101 typedef DWORD(WINAPI* WlanGetProfileFunction)(HANDLE hClientHandle,
    102                                               CONST GUID* pInterfaceGuid,
    103                                               LPCWSTR strProfileName,
    104                                               PVOID pReserved,
    105                                               LPWSTR* pstrProfileXml,
    106                                               DWORD* pdwFlags,
    107                                               DWORD* pdwGrantedAccess);
    108 
    109 typedef DWORD (WINAPI* WlanOpenHandleFunction)(
    110     DWORD dwClientVersion,
    111     PVOID pReserved,
    112     PDWORD pdwNegotiatedVersion,
    113     PHANDLE phClientHandle);
    114 
    115 typedef DWORD(WINAPI* WlanQueryInterfaceFunction)(
    116     HANDLE hClientHandle,
    117     const GUID* pInterfaceGuid,
    118     WLAN_INTF_OPCODE OpCode,
    119     PVOID pReserved,
    120     PDWORD pdwDataSize,
    121     PVOID* ppData,
    122     PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType);
    123 
    124 typedef DWORD (WINAPI* WlanRegisterNotificationFunction)(
    125     HANDLE hClientHandle,
    126     DWORD dwNotifSource,
    127     BOOL bIgnoreDuplicate,
    128     WLAN_NOTIFICATION_CALLBACK funcCallback,
    129     PVOID pCallbackContext,
    130     PVOID pReserved,
    131     PDWORD pdwPrevNotifSource);
    132 
    133 typedef DWORD (WINAPI* WlanSaveTemporaryProfileFunction)(
    134     HANDLE hClientHandle,
    135     CONST GUID* pInterfaceGuid,
    136     LPCWSTR strProfileName,
    137     LPCWSTR strAllUserProfileSecurity,
    138     DWORD dwFlags,
    139     BOOL bOverWrite,
    140     PVOID pReserved);
    141 
    142 typedef DWORD(WINAPI* WlanScanFunction)(HANDLE hClientHandle,
    143                                         CONST GUID* pInterfaceGuid,
    144                                         CONST PDOT11_SSID pDot11Ssid,
    145                                         CONST PWLAN_RAW_DATA pIeData,
    146                                         PVOID pReserved);
    147 
    148 typedef DWORD(WINAPI* WlanSetProfileFunction)(HANDLE hClientHandle,
    149                                               const GUID* pInterfaceGuid,
    150                                               DWORD dwFlags,
    151                                               LPCWSTR strProfileXml,
    152                                               LPCWSTR strAllUserProfileSecurity,
    153                                               BOOL bOverwrite,
    154                                               PVOID pReserved,
    155                                               DWORD* pdwReasonCode);
    156 
    157 // Values for WLANProfile XML.
    158 const char kAuthenticationOpen[] = "open";
    159 const char kAuthenticationWepPsk[] = "WEP";
    160 const char kAuthenticationWpaPsk[] = "WPAPSK";
    161 const char kAuthenticationWpa2Psk[] = "WPA2PSK";
    162 const char kEncryptionAES[] = "AES";
    163 const char kEncryptionNone[] = "none";
    164 const char kEncryptionTKIP[] = "TKIP";
    165 const char kEncryptionWEP[] = "WEP";
    166 const char kKeyTypeNetwork[] = "networkKey";
    167 const char kKeyTypePassphrase[] = "passPhrase";
    168 
    169 }  // namespace
    170 
    171 namespace wifi {
    172 
    173 // Implementation of WiFiService for Windows.
    174 class WiFiServiceImpl : public WiFiService {
    175  public:
    176   WiFiServiceImpl();
    177   virtual ~WiFiServiceImpl();
    178 
    179   // WiFiService interface implementation.
    180   virtual void Initialize(
    181       scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
    182 
    183   virtual void UnInitialize() OVERRIDE;
    184 
    185   virtual void GetProperties(const std::string& network_guid,
    186                              base::DictionaryValue* properties,
    187                              std::string* error) OVERRIDE;
    188 
    189   virtual void GetManagedProperties(const std::string& network_guid,
    190                                     base::DictionaryValue* managed_properties,
    191                                     std::string* error) OVERRIDE;
    192 
    193   virtual void GetState(const std::string& network_guid,
    194                         base::DictionaryValue* properties,
    195                         std::string* error) OVERRIDE;
    196 
    197   virtual void SetProperties(const std::string& network_guid,
    198                              scoped_ptr<base::DictionaryValue> properties,
    199                              std::string* error) OVERRIDE;
    200 
    201   virtual void CreateNetwork(bool shared,
    202                              scoped_ptr<base::DictionaryValue> properties,
    203                              std::string* network_guid,
    204                              std::string* error) OVERRIDE;
    205 
    206   virtual void GetVisibleNetworks(const std::string& network_type,
    207                                   base::ListValue* network_list,
    208                                   bool include_details) OVERRIDE;
    209 
    210   virtual void RequestNetworkScan() OVERRIDE;
    211 
    212   virtual void StartConnect(const std::string& network_guid,
    213                             std::string* error) OVERRIDE;
    214 
    215   virtual void StartDisconnect(const std::string& network_guid,
    216                                std::string* error) OVERRIDE;
    217 
    218   virtual void GetKeyFromSystem(const std::string& network_guid,
    219                                 std::string* key_data,
    220                                 std::string* error) OVERRIDE;
    221 
    222   virtual void SetEventObservers(
    223       scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
    224       const NetworkGuidListCallback& networks_changed_observer,
    225       const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE;
    226 
    227   virtual void RequestConnectedNetworkUpdate() OVERRIDE {}
    228 
    229  private:
    230   typedef int32 EncryptionType;
    231   enum EncryptionTypeEnum {
    232     kEncryptionTypeAny = 0,
    233     kEncryptionTypeAES = 1,
    234     kEncryptionTypeTKIP = 2
    235   };
    236 
    237   // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification
    238   // on WiFiServiceImpl passed back as |context|.
    239   static void __stdcall OnWlanNotificationCallback(
    240       PWLAN_NOTIFICATION_DATA wlan_notification_data,
    241       PVOID context);
    242 
    243   // Callback for Windows WLAN_NOTIFICATION. Called on random thread from
    244   // OnWlanNotificationCallback. Handles network connectivity and scan complete
    245   // notification and posts tasks to main thread.
    246   void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data);
    247 
    248   // Handles NetworkScanComplete notification on main thread. Sends
    249   // |NetworkListChanged| event with new list of visible networks.
    250   void OnNetworkScanCompleteOnMainThread();
    251 
    252   // Wait up to |kMaxAttempts| with |kAttemptDelayMs| delay for connection
    253   // to network with |network_guid|. Reset DHCP and Notify that |NetworkChanged|
    254   // upon success.
    255   void WaitForNetworkConnect(const std::string& network_guid, int attempt);
    256 
    257   // Check |error_code| and if is not |ERROR_SUCCESS|, then store |error_name|
    258   // into |error|.
    259   bool CheckError(DWORD error_code,
    260                   const std::string& error_name,
    261                   std::string* error) const;
    262 
    263   // Return |iterator| to network identified by |network_guid| in |networks|
    264   // list.
    265   NetworkList::iterator FindNetwork(NetworkList& networks,
    266                                     const std::string& network_guid);
    267 
    268   // Save currently connected network profile so it can be re-connected later.
    269   DWORD SaveCurrentConnectedNetwork(const NetworkProperties& properties);
    270 
    271   // Sort networks, so connected/connecting is up front, then by type:
    272   // Ethernet, WiFi, Cellular, VPN
    273   static void SortNetworks(NetworkList* networks);
    274 
    275   // Open a WLAN client handle, register for WLAN notifications.
    276   DWORD OpenClientHandle();
    277 
    278   // Reset DHCP on wireless network to work around an issue when Windows
    279   // takes forever to connect to the network, e.g. after Chromecast
    280   // device reset.
    281   DWORD ResetDHCP();
    282 
    283   // Find |adapter_index_map| by |interface_guid| for DHCP reset.
    284   DWORD FindAdapterIndexMapByGUID(const GUID& interface_guid,
    285                                   IP_ADAPTER_INDEX_MAP* adapter_index_map);
    286 
    287   // Avoid the network location wizard to pop up when network is connected.
    288   // Preserve current value in |saved_nw_category_wizard_|.
    289   DWORD DisableNwCategoryWizard();
    290 
    291   // Restore network location wizard to value saved by DisableNwCategoryWizard.
    292   DWORD RestoreNwCategoryWizard();
    293 
    294   // Ensure that |client_| handle is initialized.
    295   DWORD EnsureInitialized();
    296 
    297   // Close |client_| handle if it is open.
    298   DWORD CloseClientHandle();
    299 
    300   // Get |profile_name| from unique |network_guid|.
    301   base::string16 ProfileNameFromGUID(const std::string& network_guid) const {
    302     return base::UTF8ToUTF16(network_guid);
    303   }
    304 
    305   // Get |dot11_ssid| from unique |network_guid|.
    306   DOT11_SSID SSIDFromGUID(const std::string& network_guid) const;
    307 
    308   // Get unique |network_guid| string based on |dot11_ssid|.
    309   std::string GUIDFromSSID(const DOT11_SSID& dot11_ssid) const {
    310     return std::string(reinterpret_cast<const char*>(dot11_ssid.ucSSID),
    311                        dot11_ssid.uSSIDLength);
    312   }
    313 
    314   // Get network |ssid| string based on |wlan|.
    315   std::string SSIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const {
    316     return GUIDFromSSID(wlan.dot11Ssid);
    317   }
    318 
    319   // Get unique |network_guid| string based on |wlan|.
    320   std::string GUIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const {
    321     return SSIDFromWLAN(wlan);
    322   }
    323 
    324   // Deduce |onc::wifi| security from |alg|.
    325   std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const;
    326 
    327   // Deduce |onc::connection_state| from |wlan_state|.
    328   std::string ConnectionStateFromInterfaceState(
    329       WLAN_INTERFACE_STATE wlan_state) const;
    330 
    331   // Convert |EncryptionType| into WPA(2) encryption type string.
    332   std::string WpaEncryptionFromEncryptionType(
    333       EncryptionType encryption_type) const;
    334 
    335   // Deduce WLANProfile |authEncryption| values from |onc::wifi| security.
    336   bool AuthEncryptionFromSecurity(const std::string& security,
    337                                   EncryptionType encryption_type,
    338                                   std::string* authentication,
    339                                   std::string* encryption,
    340                                   std::string* key_type) const;
    341 
    342   // Populate |properties| based on |wlan|.
    343   void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan,
    344                                              NetworkProperties* properties);
    345 
    346   // Update |properties| based on bss info from |wlan_bss_list|. If |bssid| in
    347   // |properties| is not empty, then it is not changed and |frequency| is set
    348   // based on that bssid.
    349   void UpdateNetworkPropertiesFromBssList(const std::string& network_guid,
    350                                           const WLAN_BSS_LIST& wlan_bss_list,
    351                                           NetworkProperties* properties);
    352 
    353   // Get the list of visible wireless networks.
    354   DWORD GetVisibleNetworkList(NetworkList* network_list);
    355 
    356   // Get properties of the network currently used (connected or in transition)
    357   // by interface. Populate |current_properties| on success.
    358   DWORD GetCurrentProperties(NetworkProperties* current_properties);
    359 
    360   // Connect to network |network_guid| using previosly stored profile if exists,
    361   // or just network sid. If |frequency| is not |kFrequencyUnknown| then
    362   // connects only to BSS which uses that frequency and returns
    363   // |ERROR_NOT_FOUND| if such BSS cannot be found.
    364   DWORD Connect(const std::string& network_guid, Frequency frequency);
    365 
    366   // Disconnect from currently connected network if any.
    367   DWORD Disconnect();
    368 
    369   // Get desired connection freqency if it was set using |SetProperties|.
    370   // Default to |kFrequencyAny|.
    371   Frequency GetFrequencyToConnect(const std::string& network_guid) const;
    372 
    373   // Get DOT11_BSSID_LIST of desired BSSIDs to connect to |ssid| network on
    374   // given |frequency|.
    375   DWORD GetDesiredBssList(DOT11_SSID& ssid,
    376                           Frequency frequency,
    377                           scoped_ptr<DOT11_BSSID_LIST>* desired_list);
    378 
    379   // Normalizes |frequency_in_mhz| into one of |Frequency| values.
    380   Frequency GetNormalizedFrequency(int frequency_in_mhz) const;
    381 
    382   // Create |profile_xml| based on |network_properties|. If |encryption_type|
    383   // is |kEncryptionTypeAny| applies the type most suitable for parameters in
    384   // |network_properties|.
    385   bool CreateProfile(const NetworkProperties& network_properties,
    386                      EncryptionType encryption_type,
    387                      std::string* profile_xml);
    388 
    389   // Save temporary wireless profile for |network_guid|.
    390   DWORD SaveTempProfile(const std::string& network_guid);
    391 
    392   // Get previously stored |profile_xml| for |network_guid|.
    393   // If |get_plaintext_key| is true, and process has sufficient privileges, then
    394   // <sharedKey> data in |profile_xml| will be unprotected.
    395   DWORD GetProfile(const std::string& network_guid,
    396                    bool get_plaintext_key,
    397                    std::string* profile_xml);
    398 
    399   // Set |profile_xml| to current user or all users depending on |shared| flag.
    400   // If |overwrite| is false, then returns an error if profile exists.
    401   DWORD SetProfile(bool shared, const std::string& profile_xml, bool overwrite);
    402 
    403   // Return true if there is previously stored profile xml for |network_guid|.
    404   bool HaveProfile(const std::string& network_guid);
    405 
    406   // Delete profile that was created, but failed to connect.
    407   DWORD DeleteCreatedProfile(const std::string& network_guid);
    408 
    409   // Notify |network_list_changed_observer_| that list of visible networks has
    410   // changed to |networks|.
    411   void NotifyNetworkListChanged(const NetworkList& networks);
    412 
    413   // Notify |networks_changed_observer_| that network |network_guid| status has
    414   // changed.
    415   void NotifyNetworkChanged(const std::string& network_guid);
    416 
    417   // Load WlanApi.dll from SystemDirectory and get Api function pointers.
    418   DWORD LoadWlanLibrary();
    419   // Instance of WlanApi.dll.
    420   HINSTANCE wlan_api_library_;
    421   // WlanApi function pointers
    422   WlanConnectFunction WlanConnect_function_;
    423   WlanCloseHandleFunction WlanCloseHandle_function_;
    424   WlanDeleteProfileFunction WlanDeleteProfile_function_;
    425   WlanDisconnectFunction WlanDisconnect_function_;
    426   WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
    427   WlanFreeMemoryFunction WlanFreeMemory_function_;
    428   WlanGetAvailableNetworkListFunction WlanGetAvailableNetworkList_function_;
    429   // WlanGetNetworkBssList function may not be avaiable on Windows XP.
    430   WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_;
    431   WlanGetProfileFunction WlanGetProfile_function_;
    432   WlanOpenHandleFunction WlanOpenHandle_function_;
    433   WlanQueryInterfaceFunction WlanQueryInterface_function_;
    434   WlanRegisterNotificationFunction WlanRegisterNotification_function_;
    435   WlanScanFunction WlanScan_function_;
    436   WlanSetProfileFunction WlanSetProfile_function_;
    437   // WlanSaveTemporaryProfile function may not be avaiable on Windows XP.
    438   WlanSaveTemporaryProfileFunction WlanSaveTemporaryProfile_function_;
    439 
    440   // WLAN service handle.
    441   HANDLE client_;
    442   // GUID of the currently connected interface, if any, otherwise the GUID of
    443   // one of the WLAN interfaces.
    444   GUID interface_guid_;
    445   // Temporary storage of network properties indexed by |network_guid|. Persist
    446   // only in memory.
    447   base::DictionaryValue connect_properties_;
    448   // Preserved WLAN profile xml.
    449   std::map<std::string, std::string> saved_profiles_xml_;
    450   // Created WLAN Profiles, indexed by |network_guid|. Contains xml with TKIP
    451   // encryption type saved by |CreateNetwork| if applicable. Profile has to be
    452   // deleted if connection fails. Implicitly created profiles have to be deleted
    453   // if connection succeeds. Persist only in memory.
    454   base::DictionaryValue created_profiles_;
    455   // Observer to get notified when network(s) have changed (e.g. connect).
    456   NetworkGuidListCallback networks_changed_observer_;
    457   // Observer to get notified when network list has changed (scan complete).
    458   NetworkGuidListCallback network_list_changed_observer_;
    459   // Saved value of network location wizard show value.
    460   scoped_ptr<DWORD> saved_nw_category_wizard_;
    461   // MessageLoopProxy to post events on UI thread.
    462   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
    463   // Task runner for worker tasks.
    464   scoped_refptr<base::SequencedTaskRunner> task_runner_;
    465   // If |false|, then |networks_changed_observer_| is not notified.
    466   bool enable_notify_network_changed_;
    467   // Number of attempts to check that network has connected successfully.
    468   static const int kMaxAttempts = 100;
    469   // Delay between attempts to check that network has connected successfully.
    470   static const int kAttemptDelayMs = 100;
    471   DISALLOW_COPY_AND_ASSIGN(WiFiServiceImpl);
    472 };
    473 
    474 WiFiServiceImpl::WiFiServiceImpl()
    475     : wlan_api_library_(NULL),
    476       WlanConnect_function_(NULL),
    477       WlanCloseHandle_function_(NULL),
    478       WlanDeleteProfile_function_(NULL),
    479       WlanDisconnect_function_(NULL),
    480       WlanEnumInterfaces_function_(NULL),
    481       WlanFreeMemory_function_(NULL),
    482       WlanGetAvailableNetworkList_function_(NULL),
    483       WlanGetNetworkBssList_function_(NULL),
    484       WlanGetProfile_function_(NULL),
    485       WlanOpenHandle_function_(NULL),
    486       WlanRegisterNotification_function_(NULL),
    487       WlanSaveTemporaryProfile_function_(NULL),
    488       WlanScan_function_(NULL),
    489       WlanSetProfile_function_(NULL),
    490       client_(NULL),
    491       enable_notify_network_changed_(true) {}
    492 
    493 WiFiServiceImpl::~WiFiServiceImpl() { UnInitialize(); }
    494 
    495 void WiFiServiceImpl::Initialize(
    496     scoped_refptr<base::SequencedTaskRunner> task_runner) {
    497   DCHECK(!client_);
    498   task_runner_.swap(task_runner);
    499   // Restore NwCategoryWizard in case if we crashed during connect.
    500   RestoreNwCategoryWizard();
    501   OpenClientHandle();
    502 }
    503 
    504 void WiFiServiceImpl::UnInitialize() {
    505   CloseClientHandle();
    506 }
    507 
    508 void WiFiServiceImpl::GetProperties(const std::string& network_guid,
    509                                     base::DictionaryValue* properties,
    510                                     std::string* error) {
    511   DWORD error_code = EnsureInitialized();
    512   if (CheckError(error_code, kErrorWiFiService, error))
    513     return;
    514 
    515   NetworkProperties connected_properties;
    516   error_code = GetCurrentProperties(&connected_properties);
    517   if (error_code == ERROR_SUCCESS &&
    518       connected_properties.guid == network_guid) {
    519     properties->Swap(connected_properties.ToValue(false).get());
    520     return;
    521   }
    522 
    523   NetworkList network_list;
    524   error_code = GetVisibleNetworkList(&network_list);
    525   if (error_code == ERROR_SUCCESS) {
    526     NetworkList::const_iterator it = FindNetwork(network_list, network_guid);
    527     if (it != network_list.end()) {
    528       DVLOG(1) << "Get Properties: " << network_guid << ":"
    529                   << it->connection_state;
    530       properties->Swap(it->ToValue(false).get());
    531       return;
    532     }
    533     error_code = ERROR_NOT_FOUND;
    534   }
    535 
    536   CheckError(error_code, kErrorWiFiService, error);
    537 }
    538 
    539 void WiFiServiceImpl::GetManagedProperties(
    540     const std::string& network_guid,
    541     base::DictionaryValue* managed_properties,
    542     std::string* error) {
    543   CheckError(ERROR_CALL_NOT_IMPLEMENTED, kErrorWiFiService, error);
    544 }
    545 
    546 void WiFiServiceImpl::GetState(const std::string& network_guid,
    547                                base::DictionaryValue* properties,
    548                                std::string* error) {
    549   CheckError(ERROR_CALL_NOT_IMPLEMENTED, kErrorWiFiService, error);
    550 }
    551 
    552 void WiFiServiceImpl::SetProperties(
    553     const std::string& network_guid,
    554     scoped_ptr<base::DictionaryValue> properties,
    555     std::string* error) {
    556   // Temporary preserve WiFi properties (desired frequency, wifi password) to
    557   // use in StartConnect.
    558   DCHECK(properties.get());
    559   if (!properties->HasKey(onc::network_type::kWiFi)) {
    560     DVLOG(0) << "Missing WiFi properties:" << *properties;
    561     *error = kErrorWiFiService;
    562     return;
    563   }
    564 
    565   base::DictionaryValue* existing_properties;
    566   // If the network properties already exist, don't override previously set
    567   // properties, unless they are set in |properties|.
    568   if (connect_properties_.GetDictionaryWithoutPathExpansion(
    569           network_guid, &existing_properties)) {
    570     existing_properties->MergeDictionary(properties.get());
    571   } else {
    572     connect_properties_.SetWithoutPathExpansion(network_guid,
    573                                                 properties.release());
    574   }
    575 }
    576 
    577 void WiFiServiceImpl::CreateNetwork(
    578     bool shared,
    579     scoped_ptr<base::DictionaryValue> properties,
    580     std::string* network_guid,
    581     std::string* error) {
    582   DWORD error_code = EnsureInitialized();
    583   if (CheckError(error_code, kErrorWiFiService, error))
    584     return;
    585 
    586   NetworkProperties network_properties;
    587   if (!network_properties.UpdateFromValue(*properties)) {
    588     CheckError(ERROR_INVALID_DATA, kErrorWiFiService, error);
    589     return;
    590   }
    591 
    592   network_properties.guid = network_properties.ssid;
    593   std::string profile_xml;
    594   if (!CreateProfile(network_properties, kEncryptionTypeAny, &profile_xml)) {
    595     CheckError(ERROR_INVALID_DATA, kErrorWiFiService, error);
    596     return;
    597   }
    598 
    599   error_code = SetProfile(shared, profile_xml, false);
    600   if (CheckError(error_code, kErrorWiFiService, error)) {
    601     DVLOG(0) << profile_xml;
    602     return;
    603   }
    604 
    605   // WAP and WAP2 networks could use either AES or TKIP encryption type.
    606   // Preserve alternative profile to use in case if connection with default
    607   // encryption type fails.
    608   std::string tkip_profile_xml;
    609   if (!CreateProfile(network_properties,
    610                      kEncryptionTypeTKIP,
    611                      &tkip_profile_xml)) {
    612     CheckError(ERROR_INVALID_DATA, kErrorWiFiService, error);
    613     return;
    614   }
    615 
    616   if (tkip_profile_xml != profile_xml) {
    617     scoped_ptr<base::DictionaryValue> tkip_profile(new base::DictionaryValue());
    618     tkip_profile->SetString(kProfileXmlKey, tkip_profile_xml);
    619     tkip_profile->SetBoolean(kProfileSharedKey, shared);
    620     created_profiles_.SetWithoutPathExpansion(network_properties.guid,
    621                                               tkip_profile.release());
    622   }
    623 
    624   *network_guid = network_properties.guid;
    625 }
    626 
    627 void WiFiServiceImpl::GetVisibleNetworks(const std::string& network_type,
    628                                          base::ListValue* network_list,
    629                                          bool include_details) {
    630   if (!network_type.empty() &&
    631       network_type != onc::network_type::kAllTypes &&
    632       network_type != onc::network_type::kWiFi) {
    633     return;
    634   }
    635 
    636   DWORD error = EnsureInitialized();
    637   if (error == ERROR_SUCCESS) {
    638     NetworkList networks;
    639     error = GetVisibleNetworkList(&networks);
    640     if (error == ERROR_SUCCESS && !networks.empty()) {
    641       SortNetworks(&networks);
    642       for (NetworkList::const_iterator it = networks.begin();
    643            it != networks.end();
    644            ++it) {
    645         scoped_ptr<base::DictionaryValue> network(
    646             it->ToValue(!include_details));
    647         network_list->Append(network.release());
    648       }
    649     }
    650   }
    651 }
    652 
    653 void WiFiServiceImpl::RequestNetworkScan() {
    654   DWORD error = EnsureInitialized();
    655   if (error == ERROR_SUCCESS) {
    656     WlanScan_function_(client_, &interface_guid_, NULL, NULL, NULL);
    657   }
    658 }
    659 
    660 void WiFiServiceImpl::StartConnect(const std::string& network_guid,
    661                                    std::string* error) {
    662   DVLOG(1) << "Start Connect: " << network_guid;
    663   DWORD error_code = EnsureInitialized();
    664   if (CheckError(error_code, kErrorWiFiService, error))
    665     return;
    666 
    667   // Check, if the network is already connected on desired frequency.
    668   Frequency frequency = GetFrequencyToConnect(network_guid);
    669   NetworkProperties properties;
    670   GetCurrentProperties(&properties);
    671   bool already_connected =
    672       network_guid == properties.guid &&
    673       properties.connection_state == onc::connection_state::kConnected &&
    674       (frequency == kFrequencyAny || frequency == properties.frequency);
    675 
    676   // Connect only if network |network_guid| is not connected already.
    677   if (!already_connected) {
    678     SaveCurrentConnectedNetwork(properties);
    679     error_code = Connect(network_guid, frequency);
    680   }
    681   if (error_code == ERROR_SUCCESS) {
    682     // Notify that previously connected network has changed.
    683     NotifyNetworkChanged(properties.guid);
    684     // Start waiting for network connection state change.
    685     if (!networks_changed_observer_.is_null()) {
    686       DisableNwCategoryWizard();
    687       // Disable automatic network change notifications as they get fired
    688       // when network is just connected, but not yet accessible (doesn't
    689       // have valid IP address).
    690       enable_notify_network_changed_ = false;
    691       WaitForNetworkConnect(network_guid, 0);
    692       return;
    693     }
    694   } else if (error_code == ERROR_ACCESS_DENIED) {
    695     CheckError(error_code, kErrorNotConfigured, error);
    696   } else {
    697     CheckError(error_code, kErrorWiFiService, error);
    698   }
    699 }
    700 
    701 void WiFiServiceImpl::StartDisconnect(const std::string& network_guid,
    702                                       std::string* error) {
    703   DVLOG(1) << "Start Disconnect: " << network_guid;
    704   DWORD error_code = EnsureInitialized();
    705   if (CheckError(error_code, kErrorWiFiService, error))
    706     return;
    707 
    708   // Check, if the network is currently connected.
    709   NetworkProperties properties;
    710   GetCurrentProperties(&properties);
    711   if (network_guid == properties.guid) {
    712     if (properties.connection_state == onc::connection_state::kConnected)
    713       SaveCurrentConnectedNetwork(properties);
    714     error_code = Disconnect();
    715     if (error_code == ERROR_SUCCESS) {
    716       NotifyNetworkChanged(network_guid);
    717       return;
    718     }
    719   }
    720   CheckError(error_code, kErrorWiFiService, error);
    721 }
    722 
    723 void WiFiServiceImpl::GetKeyFromSystem(const std::string& network_guid,
    724                                        std::string* key_data,
    725                                        std::string* error) {
    726   DWORD error_code = EnsureInitialized();
    727   if (CheckError(error_code, kErrorWiFiService, error))
    728     return;
    729 
    730   std::string profile_xml;
    731   error_code = GetProfile(network_guid, true, &profile_xml);
    732   if (CheckError(error_code, kErrorWiFiService, error))
    733     return;
    734 
    735   const char kSharedKeyElement[] = "sharedKey";
    736   const char kProtectedElement[] = "protected";
    737   const char kKeyMaterialElement[] = "keyMaterial";
    738 
    739   // Quick check to verify presence of <sharedKey> element.
    740   if (profile_xml.find(kSharedKeyElement) == std::string::npos) {
    741     *error = kErrorWiFiService;
    742     return;
    743   }
    744 
    745   XmlReader reader;
    746   if (reader.Load(profile_xml)) {
    747     while (reader.Read()) {
    748       reader.SkipToElement();
    749       if (reader.NodeName() == kSharedKeyElement) {
    750         while (reader.Read()) {
    751           reader.SkipToElement();
    752           if (reader.NodeName() == kKeyMaterialElement) {
    753             reader.ReadElementContent(key_data);
    754           } else if (reader.NodeName() == kProtectedElement) {
    755             std::string protected_data;
    756             reader.ReadElementContent(&protected_data);
    757             // Without UAC privilege escalation call to |GetProfile| with
    758             // |WLAN_PROFILE_GET_PLAINTEXT_KEY| flag returns success, but has
    759             // protected keyMaterial. Report an error in this case.
    760             if (protected_data != "false") {
    761               *error = kErrorWiFiService;
    762               break;
    763             }
    764           }
    765         }
    766         return;
    767       }
    768     }
    769   }
    770 
    771   // Did not find passphrase in the profile.
    772   *error = kErrorWiFiService;
    773 }
    774 
    775 void WiFiServiceImpl::SetEventObservers(
    776     scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
    777     const NetworkGuidListCallback& networks_changed_observer,
    778     const NetworkGuidListCallback& network_list_changed_observer) {
    779   DWORD error_code = EnsureInitialized();
    780   if (error_code != ERROR_SUCCESS)
    781     return;
    782   message_loop_proxy_.swap(message_loop_proxy);
    783   if (!networks_changed_observer_.is_null() ||
    784       !network_list_changed_observer_.is_null()) {
    785     // Stop listening to WLAN notifications.
    786     WlanRegisterNotification_function_(client_,
    787                                        WLAN_NOTIFICATION_SOURCE_NONE,
    788                                        FALSE,
    789                                        OnWlanNotificationCallback,
    790                                        this,
    791                                        NULL,
    792                                        NULL);
    793   }
    794   networks_changed_observer_ = networks_changed_observer;
    795   network_list_changed_observer_ = network_list_changed_observer;
    796   if (!networks_changed_observer_.is_null() ||
    797       !network_list_changed_observer_.is_null()) {
    798     // Start listening to WLAN notifications.
    799     WlanRegisterNotification_function_(client_,
    800                                        WLAN_NOTIFICATION_SOURCE_ALL,
    801                                        FALSE,
    802                                        OnWlanNotificationCallback,
    803                                        this,
    804                                        NULL,
    805                                        NULL);
    806   }
    807 }
    808 
    809 void WiFiServiceImpl::OnWlanNotificationCallback(
    810     PWLAN_NOTIFICATION_DATA wlan_notification_data,
    811     PVOID context) {
    812   WiFiServiceImpl* service = reinterpret_cast<WiFiServiceImpl*>(context);
    813   service->OnWlanNotification(wlan_notification_data);
    814 }
    815 
    816 void WiFiServiceImpl::OnWlanNotification(
    817     PWLAN_NOTIFICATION_DATA wlan_notification_data) {
    818   if (message_loop_proxy_ == NULL)
    819     return;
    820   switch (wlan_notification_data->NotificationCode) {
    821     case wlan_notification_acm_disconnected:
    822     case wlan_notification_acm_connection_complete:
    823     case wlan_notification_acm_connection_attempt_fail: {
    824       PWLAN_CONNECTION_NOTIFICATION_DATA wlan_connection_data =
    825           reinterpret_cast<PWLAN_CONNECTION_NOTIFICATION_DATA>(
    826               wlan_notification_data->pData);
    827       message_loop_proxy_->PostTask(
    828           FROM_HERE,
    829           base::Bind(&WiFiServiceImpl::NotifyNetworkChanged,
    830                      base::Unretained(this),
    831                      GUIDFromSSID(wlan_connection_data->dot11Ssid)));
    832       break;
    833     }
    834     case wlan_notification_acm_scan_complete:
    835     case wlan_notification_acm_interface_removal:
    836       message_loop_proxy_->PostTask(
    837           FROM_HERE,
    838           base::Bind(&WiFiServiceImpl::OnNetworkScanCompleteOnMainThread,
    839                      base::Unretained(this)));
    840       break;
    841   }
    842 }
    843 
    844 void WiFiServiceImpl::OnNetworkScanCompleteOnMainThread() {
    845   NetworkList networks;
    846   // Get current list of visible networks and notify that network list has
    847   // changed.
    848   DWORD error = GetVisibleNetworkList(&networks);
    849   if (error != ERROR_SUCCESS)
    850     networks.clear();
    851   NotifyNetworkListChanged(networks);
    852 }
    853 
    854 void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid,
    855                                             int attempt) {
    856   // If network didn't get connected in |kMaxAttempts|, then try to connect
    857   // using different profile if it was created recently.
    858   if (attempt > kMaxAttempts) {
    859     LOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to "
    860                << network_guid;
    861 
    862     base::DictionaryValue* created_profile = NULL;
    863     // Check, whether this connection is using newly created profile.
    864     if (created_profiles_.GetDictionaryWithoutPathExpansion(
    865         network_guid, &created_profile)) {
    866       std::string tkip_profile_xml;
    867       bool shared = false;
    868       // Check, if this connection there is alternative TKIP profile xml that
    869       // should be tried. If there is, then set it up and try to connect again.
    870       if (created_profile->GetString(kProfileXmlKey, &tkip_profile_xml) &&
    871           created_profile->GetBoolean(kProfileSharedKey, &shared)) {
    872         // Remove TKIP profile xml, so it will not be tried again.
    873         created_profile->Remove(kProfileXmlKey, NULL);
    874         created_profile->Remove(kProfileSharedKey, NULL);
    875         DWORD error_code = SetProfile(shared, tkip_profile_xml, true);
    876         if (error_code == ERROR_SUCCESS) {
    877           // Try to connect with new profile.
    878           error_code = Connect(network_guid,
    879                                GetFrequencyToConnect(network_guid));
    880           if (error_code == ERROR_SUCCESS) {
    881             // Start waiting again.
    882             WaitForNetworkConnect(network_guid, 0);
    883             return;
    884           } else {
    885             LOG(ERROR) << "Failed to set created profile for " << network_guid
    886                        << " error=" << error_code;
    887           }
    888         }
    889       } else {
    890         // Connection has failed, so delete bad created profile.
    891         DWORD error_code = DeleteCreatedProfile(network_guid);
    892         if (error_code != ERROR_SUCCESS) {
    893           LOG(ERROR) << "Failed to delete created profile for " << network_guid
    894                      << " error=" << error_code;
    895         }
    896       }
    897     }
    898     // Restore automatic network change notifications and stop waiting.
    899     enable_notify_network_changed_ = true;
    900     RestoreNwCategoryWizard();
    901     return;
    902   }
    903   NetworkProperties current_properties;
    904   DWORD error = GetCurrentProperties(&current_properties);
    905   if (network_guid == current_properties.guid &&
    906       current_properties.connection_state ==
    907           onc::connection_state::kConnected) {
    908     DVLOG(1) << "WiFi Connected, Reset DHCP: " << network_guid;
    909     // Even though wireless network is now connected, it may still be unusable,
    910     // e.g. after Chromecast device reset. Reset DHCP on wireless network to
    911     // work around this issue.
    912     error = ResetDHCP();
    913     if (error != ERROR_SUCCESS)
    914       LOG(ERROR) << error;
    915     // There is no need to keep created profile as network is connected.
    916     created_profiles_.RemoveWithoutPathExpansion(network_guid, NULL);
    917     // Restore previously suppressed notifications.
    918     enable_notify_network_changed_ = true;
    919     RestoreNwCategoryWizard();
    920     NotifyNetworkChanged(network_guid);
    921   } else {
    922     // Continue waiting for network connection state change.
    923     task_runner_->PostDelayedTask(
    924         FROM_HERE,
    925         base::Bind(&WiFiServiceImpl::WaitForNetworkConnect,
    926                    base::Unretained(this),
    927                    network_guid,
    928                    ++attempt),
    929         base::TimeDelta::FromMilliseconds(kAttemptDelayMs));
    930   }
    931 }
    932 
    933 bool WiFiServiceImpl::CheckError(DWORD error_code,
    934                                  const std::string& error_name,
    935                                  std::string* error) const {
    936   if (error_code != ERROR_SUCCESS) {
    937     DLOG(ERROR) << "WiFiService Error " << error_code << ": " << error_name;
    938     *error = error_name;
    939     return true;
    940   }
    941   return false;
    942 }
    943 
    944 NetworkList::iterator WiFiServiceImpl::FindNetwork(
    945     NetworkList& networks,
    946     const std::string& network_guid) {
    947   for (NetworkList::iterator it = networks.begin(); it != networks.end();
    948        ++it) {
    949     if (it->guid == network_guid)
    950       return it;
    951   }
    952   return networks.end();
    953 }
    954 
    955 DWORD WiFiServiceImpl::SaveCurrentConnectedNetwork(
    956     const NetworkProperties& current_properties) {
    957   DWORD error = ERROR_SUCCESS;
    958   // Save currently connected network.
    959   if (!current_properties.guid.empty() &&
    960       current_properties.connection_state ==
    961           onc::connection_state::kConnected) {
    962     error = SaveTempProfile(current_properties.guid);
    963   }
    964   return error;
    965 }
    966 
    967 void WiFiServiceImpl::SortNetworks(NetworkList* networks) {
    968   networks->sort(NetworkProperties::OrderByType);
    969 }
    970 
    971 DWORD WiFiServiceImpl::LoadWlanLibrary() {
    972   // Use an absolute path to load the DLL to avoid DLL preloading attacks.
    973   base::FilePath path;
    974   if (!PathService::Get(base::DIR_SYSTEM, &path)) {
    975     LOG(ERROR) << "Unable to get system path.";
    976     return ERROR_NOT_FOUND;
    977   }
    978   wlan_api_library_ = ::LoadLibraryEx(path.Append(kWlanApiDll).value().c_str(),
    979                                       NULL,
    980                                       LOAD_WITH_ALTERED_SEARCH_PATH);
    981   if (!wlan_api_library_) {
    982     LOG(ERROR) << "Unable to load WlanApi.dll.";
    983     return ERROR_NOT_FOUND;
    984   }
    985 
    986   // Initialize WlanApi function pointers
    987   WlanConnect_function_ =
    988       reinterpret_cast<WlanConnectFunction>(
    989           ::GetProcAddress(wlan_api_library_, kWlanConnect));
    990   WlanCloseHandle_function_ =
    991       reinterpret_cast<WlanCloseHandleFunction>(
    992           ::GetProcAddress(wlan_api_library_, kWlanCloseHandle));
    993   WlanDeleteProfile_function_ =
    994       reinterpret_cast<WlanDeleteProfileFunction>(
    995           ::GetProcAddress(wlan_api_library_, kWlanDeleteProfile));
    996   WlanDisconnect_function_ =
    997       reinterpret_cast<WlanDisconnectFunction>(
    998           ::GetProcAddress(wlan_api_library_, kWlanDisconnect));
    999   WlanEnumInterfaces_function_ =
   1000       reinterpret_cast<WlanEnumInterfacesFunction>(
   1001           ::GetProcAddress(wlan_api_library_, kWlanEnumInterfaces));
   1002   WlanFreeMemory_function_ =
   1003       reinterpret_cast<WlanFreeMemoryFunction>(
   1004           ::GetProcAddress(wlan_api_library_, kWlanFreeMemory));
   1005   WlanGetAvailableNetworkList_function_ =
   1006       reinterpret_cast<WlanGetAvailableNetworkListFunction>(
   1007           ::GetProcAddress(wlan_api_library_, kWlanGetAvailableNetworkList));
   1008   WlanGetNetworkBssList_function_ =
   1009       reinterpret_cast<WlanGetNetworkBssListFunction>(
   1010           ::GetProcAddress(wlan_api_library_, kWlanGetNetworkBssList));
   1011   WlanGetProfile_function_ =
   1012       reinterpret_cast<WlanGetProfileFunction>(
   1013           ::GetProcAddress(wlan_api_library_, kWlanGetProfile));
   1014   WlanOpenHandle_function_ =
   1015       reinterpret_cast<WlanOpenHandleFunction>(
   1016           ::GetProcAddress(wlan_api_library_, kWlanOpenHandle));
   1017   WlanQueryInterface_function_ =
   1018       reinterpret_cast<WlanQueryInterfaceFunction>(
   1019           ::GetProcAddress(wlan_api_library_, kWlanQueryInterface));
   1020   WlanRegisterNotification_function_ =
   1021       reinterpret_cast<WlanRegisterNotificationFunction>(
   1022           ::GetProcAddress(wlan_api_library_, kWlanRegisterNotification));
   1023   WlanSaveTemporaryProfile_function_ =
   1024       reinterpret_cast<WlanSaveTemporaryProfileFunction>(
   1025           ::GetProcAddress(wlan_api_library_, kWlanSaveTemporaryProfile));
   1026   WlanScan_function_ =
   1027       reinterpret_cast<WlanScanFunction>(
   1028           ::GetProcAddress(wlan_api_library_, kWlanScan));
   1029   WlanSetProfile_function_ =
   1030       reinterpret_cast<WlanSetProfileFunction>(
   1031           ::GetProcAddress(wlan_api_library_, kWlanSetProfile));
   1032 
   1033   if (!WlanConnect_function_ ||
   1034       !WlanCloseHandle_function_ ||
   1035       !WlanDeleteProfile_function_ ||
   1036       !WlanDisconnect_function_ ||
   1037       !WlanEnumInterfaces_function_ ||
   1038       !WlanFreeMemory_function_ ||
   1039       !WlanGetAvailableNetworkList_function_ ||
   1040       !WlanGetProfile_function_ ||
   1041       !WlanOpenHandle_function_ ||
   1042       !WlanQueryInterface_function_ ||
   1043       !WlanRegisterNotification_function_ ||
   1044       !WlanScan_function_ ||
   1045       !WlanSetProfile_function_) {
   1046     LOG(ERROR) << "Unable to find required WlanApi function.";
   1047     FreeLibrary(wlan_api_library_);
   1048     wlan_api_library_ = NULL;
   1049     return ERROR_NOT_FOUND;
   1050   }
   1051 
   1052   // Some WlanApi functions may not be available on XP.
   1053   if (!WlanGetNetworkBssList_function_ ||
   1054       !WlanSaveTemporaryProfile_function_) {
   1055     DVLOG(1) << "WlanApi function is not be available on XP.";
   1056   }
   1057 
   1058   return ERROR_SUCCESS;
   1059 }
   1060 
   1061 DWORD WiFiServiceImpl::OpenClientHandle() {
   1062   DWORD error = LoadWlanLibrary();
   1063   DWORD service_version = 0;
   1064 
   1065   if (error != ERROR_SUCCESS)
   1066     return error;
   1067 
   1068   // Open a handle to the service.
   1069   error = WlanOpenHandle_function_(1, NULL, &service_version, &client_);
   1070 
   1071   PWLAN_INTERFACE_INFO_LIST interface_list = NULL;
   1072   if (error == ERROR_SUCCESS) {
   1073     // Enumerate wireless interfaces.
   1074     error = WlanEnumInterfaces_function_(client_, NULL, &interface_list);
   1075     if (error == ERROR_SUCCESS) {
   1076       if (interface_list != NULL && interface_list->dwNumberOfItems != 0) {
   1077         // Remember first interface just in case if none are connected.
   1078         interface_guid_ = interface_list->InterfaceInfo[0].InterfaceGuid;
   1079         // Try to find a connected interface.
   1080         for (DWORD itf = 0; itf < interface_list->dwNumberOfItems; ++itf) {
   1081           if (interface_list->InterfaceInfo[itf].isState ==
   1082               wlan_interface_state_connected) {
   1083             // Found connected interface, remember it!
   1084             interface_guid_ = interface_list->InterfaceInfo[itf].InterfaceGuid;
   1085             break;
   1086           }
   1087         }
   1088       } else {
   1089         error = ERROR_NOINTERFACE;
   1090       }
   1091     }
   1092     // Clean up..
   1093     if (interface_list != NULL)
   1094       WlanFreeMemory_function_(interface_list);
   1095   }
   1096   return error;
   1097 }
   1098 
   1099 DWORD WiFiServiceImpl::ResetDHCP() {
   1100   IP_ADAPTER_INDEX_MAP adapter_index_map = {0};
   1101   DWORD error = FindAdapterIndexMapByGUID(interface_guid_, &adapter_index_map);
   1102   if (error != ERROR_SUCCESS) {
   1103     LOG(ERROR) << error;
   1104     return error;
   1105   }
   1106   error = ::IpReleaseAddress(&adapter_index_map);
   1107   if (error != ERROR_SUCCESS) {
   1108     if (error != ERROR_ADDRESS_NOT_ASSOCIATED) {
   1109       LOG(ERROR) << error;
   1110       return error;
   1111     }
   1112     DVLOG(1) << "Ignoring IpReleaseAddress Error: " << error;
   1113   }
   1114   error = ::IpRenewAddress(&adapter_index_map);
   1115   if (error != ERROR_SUCCESS)
   1116     LOG(ERROR) << error;
   1117   return error;
   1118 }
   1119 
   1120 DWORD WiFiServiceImpl::FindAdapterIndexMapByGUID(
   1121     const GUID& interface_guid,
   1122     IP_ADAPTER_INDEX_MAP* adapter_index_map) {
   1123   base::string16 guid_string;
   1124   const int kGUIDSize = 39;
   1125   ::StringFromGUID2(
   1126       interface_guid, WriteInto(&guid_string, kGUIDSize), kGUIDSize);
   1127 
   1128   ULONG buffer_length = 0;
   1129   DWORD error = ::GetInterfaceInfo(NULL, &buffer_length);
   1130   if (error == ERROR_INSUFFICIENT_BUFFER) {
   1131     scoped_ptr<unsigned char[]> buffer(new unsigned char[buffer_length]);
   1132     IP_INTERFACE_INFO* interface_info =
   1133         reinterpret_cast<IP_INTERFACE_INFO*>(buffer.get());
   1134     error = GetInterfaceInfo(interface_info, &buffer_length);
   1135     if (error == ERROR_SUCCESS) {
   1136       for (int adapter = 0; adapter < interface_info->NumAdapters; ++adapter) {
   1137         if (EndsWith(
   1138                 interface_info->Adapter[adapter].Name, guid_string, false)) {
   1139           *adapter_index_map = interface_info->Adapter[adapter];
   1140           break;
   1141         }
   1142       }
   1143     }
   1144   }
   1145   return error;
   1146 }
   1147 
   1148 DWORD WiFiServiceImpl::DisableNwCategoryWizard() {
   1149   base::win::RegKey nw_category_wizard;
   1150   DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER,
   1151                                         kNwCategoryWizardRegKey,
   1152                                         KEY_READ | KEY_SET_VALUE);
   1153   if (error == ERROR_SUCCESS) {
   1154     // Save current value if present.
   1155     if (nw_category_wizard.HasValue(kNwCategoryWizardRegValue)) {
   1156       DWORD saved = 0u;
   1157       error = nw_category_wizard.ReadValueDW(kNwCategoryWizardRegValue,
   1158                                              &saved);
   1159       if (error == ERROR_SUCCESS) {
   1160         error = nw_category_wizard.WriteValue(kNwCategoryWizardSavedRegValue,
   1161                                               saved);
   1162       }
   1163     } else {
   1164       // Mark that temporary value has to be deleted.
   1165       error = nw_category_wizard.WriteValue(kNwCategoryWizardDeleteRegValue,
   1166                                             1u);
   1167     }
   1168 
   1169     // Disable network location wizard.
   1170     error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue,
   1171                                           static_cast<DWORD>(0));
   1172   }
   1173 
   1174   return error;
   1175 }
   1176 
   1177 DWORD WiFiServiceImpl::RestoreNwCategoryWizard() {
   1178   base::win::RegKey nw_category_wizard;
   1179   DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER,
   1180                                         kNwCategoryWizardRegKey,
   1181                                         KEY_SET_VALUE);
   1182   if (error == ERROR_SUCCESS) {
   1183     // Restore saved value if present.
   1184     if (nw_category_wizard.HasValue(kNwCategoryWizardSavedRegValue)) {
   1185       DWORD saved = 0u;
   1186       error = nw_category_wizard.ReadValueDW(kNwCategoryWizardSavedRegValue,
   1187                                              &saved);
   1188       if (error == ERROR_SUCCESS) {
   1189         error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue,
   1190                                               saved);
   1191         error = nw_category_wizard.DeleteValue(kNwCategoryWizardSavedRegValue);
   1192       }
   1193     } else if (nw_category_wizard.HasValue(kNwCategoryWizardDeleteRegValue)) {
   1194       error = nw_category_wizard.DeleteValue(kNwCategoryWizardRegValue);
   1195       error = nw_category_wizard.DeleteValue(kNwCategoryWizardDeleteRegValue);
   1196     }
   1197   }
   1198 
   1199   return error;
   1200 }
   1201 
   1202 DWORD WiFiServiceImpl::EnsureInitialized() {
   1203   if (client_ != NULL)
   1204     return ERROR_SUCCESS;
   1205   return ERROR_NOINTERFACE;
   1206 }
   1207 
   1208 DWORD WiFiServiceImpl::CloseClientHandle() {
   1209   DWORD error = ERROR_SUCCESS;
   1210   if (client_ != NULL) {
   1211     error = WlanCloseHandle_function_(client_, NULL);
   1212     client_ = NULL;
   1213   }
   1214   if (wlan_api_library_ != NULL) {
   1215     WlanConnect_function_ = NULL;
   1216     WlanCloseHandle_function_ = NULL;
   1217     WlanDeleteProfile_function_ = NULL;
   1218     WlanDisconnect_function_ = NULL;
   1219     WlanEnumInterfaces_function_ = NULL;
   1220     WlanFreeMemory_function_ = NULL;
   1221     WlanGetAvailableNetworkList_function_ = NULL;
   1222     WlanGetNetworkBssList_function_ = NULL;
   1223     WlanGetProfile_function_ = NULL;
   1224     WlanOpenHandle_function_ = NULL;
   1225     WlanRegisterNotification_function_ = NULL;
   1226     WlanSaveTemporaryProfile_function_ = NULL;
   1227     WlanScan_function_ = NULL;
   1228     WlanSetProfile_function_ = NULL;
   1229     ::FreeLibrary(wlan_api_library_);
   1230     wlan_api_library_ = NULL;
   1231   }
   1232   return error;
   1233 }
   1234 
   1235 DOT11_SSID WiFiServiceImpl::SSIDFromGUID(
   1236     const std::string& network_guid) const {
   1237   DOT11_SSID ssid = {0};
   1238   if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) {
   1239     ssid.uSSIDLength = static_cast<ULONG>(network_guid.length());
   1240     strncpy(reinterpret_cast<char*>(ssid.ucSSID),
   1241             network_guid.c_str(),
   1242             ssid.uSSIDLength);
   1243   } else {
   1244     NOTREACHED();
   1245   }
   1246   return ssid;
   1247 }
   1248 
   1249 std::string WiFiServiceImpl::SecurityFromDot11AuthAlg(
   1250     DOT11_AUTH_ALGORITHM alg) const {
   1251   switch (alg) {
   1252     case DOT11_AUTH_ALGO_RSNA:
   1253       return onc::wifi::kWPA_EAP;
   1254     case DOT11_AUTH_ALGO_RSNA_PSK:
   1255       return onc::wifi::kWPA_PSK;
   1256     case DOT11_AUTH_ALGO_80211_SHARED_KEY:
   1257       return onc::wifi::kWEP_PSK;
   1258     case DOT11_AUTH_ALGO_80211_OPEN:
   1259       return onc::wifi::kNone;
   1260     default:
   1261       return onc::wifi::kWPA_EAP;
   1262   }
   1263 }
   1264 
   1265 std::string WiFiServiceImpl::ConnectionStateFromInterfaceState(
   1266     WLAN_INTERFACE_STATE wlan_state) const {
   1267   switch (wlan_state) {
   1268     case wlan_interface_state_connected:
   1269       // TODO(mef): Even if |wlan_state| is connected, the network may still
   1270       // not be reachable, and should be resported as |kConnecting|.
   1271       return onc::connection_state::kConnected;
   1272     case wlan_interface_state_associating:
   1273     case wlan_interface_state_discovering:
   1274     case wlan_interface_state_authenticating:
   1275       return onc::connection_state::kConnecting;
   1276     default:
   1277       return onc::connection_state::kNotConnected;
   1278   }
   1279 }
   1280 
   1281 void WiFiServiceImpl::NetworkPropertiesFromAvailableNetwork(
   1282     const WLAN_AVAILABLE_NETWORK& wlan,
   1283     NetworkProperties* properties) {
   1284   // TODO(mef): It would be nice for the connection states in
   1285   // getVisibleNetworks and getProperties results to be consistent.
   1286   if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) {
   1287     properties->connection_state = onc::connection_state::kConnected;
   1288   } else {
   1289     properties->connection_state = onc::connection_state::kNotConnected;
   1290   }
   1291 
   1292   properties->ssid = SSIDFromWLAN(wlan);
   1293   properties->name = properties->ssid;
   1294   properties->guid = GUIDFromWLAN(wlan);
   1295   properties->type = onc::network_type::kWiFi;
   1296   properties->security =
   1297       SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm);
   1298   properties->signal_strength = wlan.wlanSignalQuality;
   1299 }
   1300 
   1301 void WiFiServiceImpl::UpdateNetworkPropertiesFromBssList(
   1302     const std::string& network_guid,
   1303     const WLAN_BSS_LIST& wlan_bss_list,
   1304     NetworkProperties* properties) {
   1305   if (network_guid.empty())
   1306     return;
   1307 
   1308   DOT11_SSID ssid = SSIDFromGUID(network_guid);
   1309   for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) {
   1310     const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]);
   1311     if (bss_entry.dot11Ssid.uSSIDLength == ssid.uSSIDLength &&
   1312         0 == memcmp(bss_entry.dot11Ssid.ucSSID,
   1313                     ssid.ucSSID,
   1314                     bss_entry.dot11Ssid.uSSIDLength)) {
   1315       std::string bssid = NetworkProperties::MacAddressAsString(
   1316           bss_entry.dot11Bssid);
   1317       Frequency frequency = GetNormalizedFrequency(
   1318           bss_entry.ulChCenterFrequency / 1000);
   1319       properties->frequency_set.insert(frequency);
   1320       if (properties->bssid.empty() || properties->bssid == bssid) {
   1321         properties->frequency = frequency;
   1322         properties->bssid = bssid;
   1323       }
   1324     }
   1325   }
   1326 }
   1327 
   1328 // Get the list of visible wireless networks
   1329 DWORD WiFiServiceImpl::GetVisibleNetworkList(NetworkList* network_list) {
   1330   if (client_ == NULL) {
   1331     NOTREACHED();
   1332     return ERROR_NOINTERFACE;
   1333   }
   1334 
   1335   DWORD error = ERROR_SUCCESS;
   1336   PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL;
   1337   PWLAN_BSS_LIST bss_list = NULL;
   1338 
   1339   error = WlanGetAvailableNetworkList_function_(
   1340       client_,
   1341       &interface_guid_,
   1342       WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES,
   1343       NULL,
   1344       &available_network_list);
   1345 
   1346   std::set<std::string> network_guids;
   1347 
   1348   if (error == ERROR_SUCCESS &&
   1349       available_network_list &&
   1350       WlanGetNetworkBssList_function_) {
   1351     // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is
   1352     // needed, then different method of getting BSS (e.g. OID query) will have
   1353     // to be used.
   1354     error = WlanGetNetworkBssList_function_(client_,
   1355                                             &interface_guid_,
   1356                                             NULL,
   1357                                             dot11_BSS_type_any,
   1358                                             FALSE,
   1359                                             NULL,
   1360                                             &bss_list);
   1361     if (error == ERROR_SUCCESS && NULL != bss_list) {
   1362       for (DWORD i = 0; i < available_network_list->dwNumberOfItems; ++i) {
   1363         NetworkProperties network_properties;
   1364         NetworkPropertiesFromAvailableNetwork(
   1365             available_network_list->Network[i],
   1366             &network_properties);
   1367         UpdateNetworkPropertiesFromBssList(network_properties.guid,
   1368                                            *bss_list,
   1369                                            &network_properties);
   1370         // Check for duplicate network guids.
   1371         if (network_guids.count(network_properties.guid)) {
   1372           // There should be no difference between properties except for
   1373           // |connection_state|, so mark it as |kConnected| if either one is.
   1374           if (network_properties.connection_state ==
   1375               onc::connection_state::kConnected) {
   1376             NetworkList::iterator previous_network_properties =
   1377                 FindNetwork(*network_list, network_properties.guid);
   1378             DCHECK(previous_network_properties != network_list->end());
   1379             previous_network_properties->connection_state =
   1380                 network_properties.connection_state;
   1381           }
   1382         } else {
   1383           network_list->push_back(network_properties);
   1384         }
   1385         network_guids.insert(network_properties.guid);
   1386       }
   1387     }
   1388   }
   1389 
   1390   // Clean up.
   1391   if (available_network_list != NULL) {
   1392     WlanFreeMemory_function_(available_network_list);
   1393   }
   1394   if (bss_list != NULL) {
   1395     WlanFreeMemory_function_(bss_list);
   1396   }
   1397   return error;
   1398 }
   1399 
   1400 DWORD WiFiServiceImpl::GetCurrentProperties(NetworkProperties* properties) {
   1401   if (client_ == NULL) {
   1402     NOTREACHED();
   1403     return ERROR_NOINTERFACE;
   1404   }
   1405 
   1406   // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is
   1407   // needed, then different method of getting BSS (e.g. OID query) will have
   1408   // to be used.
   1409   if (WlanGetNetworkBssList_function_ == NULL)
   1410     return ERROR_NOINTERFACE;
   1411 
   1412   DWORD error = ERROR_SUCCESS;
   1413   DWORD data_size = 0;
   1414   PWLAN_CONNECTION_ATTRIBUTES wlan_connection_attributes = NULL;
   1415   PWLAN_BSS_LIST bss_list = NULL;
   1416   error = WlanQueryInterface_function_(
   1417       client_,
   1418       &interface_guid_,
   1419       wlan_intf_opcode_current_connection,
   1420       NULL,
   1421       &data_size,
   1422       reinterpret_cast<PVOID*>(&wlan_connection_attributes),
   1423       NULL);
   1424   if (error == ERROR_SUCCESS &&
   1425       wlan_connection_attributes != NULL) {
   1426     WLAN_ASSOCIATION_ATTRIBUTES& connected_wlan =
   1427         wlan_connection_attributes->wlanAssociationAttributes;
   1428 
   1429     properties->connection_state = ConnectionStateFromInterfaceState(
   1430         wlan_connection_attributes->isState);
   1431     properties->ssid = GUIDFromSSID(connected_wlan.dot11Ssid);
   1432     properties->name = properties->ssid;
   1433     properties->guid = GUIDFromSSID(connected_wlan.dot11Ssid);
   1434     properties->type = onc::network_type::kWiFi;
   1435     properties->bssid = NetworkProperties::MacAddressAsString(
   1436         connected_wlan.dot11Bssid);
   1437     properties->security = SecurityFromDot11AuthAlg(
   1438         wlan_connection_attributes->wlanSecurityAttributes.dot11AuthAlgorithm);
   1439     properties->signal_strength = connected_wlan.wlanSignalQuality;
   1440 
   1441     error = WlanGetNetworkBssList_function_(client_,
   1442                                             &interface_guid_,
   1443                                             &connected_wlan.dot11Ssid,
   1444                                             connected_wlan.dot11BssType,
   1445                                             FALSE,
   1446                                             NULL,
   1447                                             &bss_list);
   1448     if (error == ERROR_SUCCESS && NULL != bss_list) {
   1449       UpdateNetworkPropertiesFromBssList(properties->guid,
   1450                                          *bss_list,
   1451                                          properties);
   1452     }
   1453   }
   1454 
   1455   // Clean up.
   1456   if (wlan_connection_attributes != NULL)
   1457     WlanFreeMemory_function_(wlan_connection_attributes);
   1458 
   1459   if (bss_list != NULL)
   1460     WlanFreeMemory_function_(bss_list);
   1461 
   1462   return error;
   1463 }
   1464 
   1465 Frequency WiFiServiceImpl::GetFrequencyToConnect(
   1466     const std::string& network_guid) const {
   1467   // Check whether desired frequency is set in |connect_properties_|.
   1468   const base::DictionaryValue* properties;
   1469   const base::DictionaryValue* wifi;
   1470   int frequency;
   1471   if (connect_properties_.GetDictionaryWithoutPathExpansion(
   1472           network_guid, &properties) &&
   1473       properties->GetDictionary(onc::network_type::kWiFi, &wifi) &&
   1474       wifi->GetInteger(onc::wifi::kFrequency, &frequency)) {
   1475     return GetNormalizedFrequency(frequency);
   1476   }
   1477   return kFrequencyAny;
   1478 }
   1479 
   1480 DWORD WiFiServiceImpl::GetDesiredBssList(
   1481     DOT11_SSID& ssid,
   1482     Frequency frequency,
   1483     scoped_ptr<DOT11_BSSID_LIST>* desired_list) {
   1484   if (client_ == NULL) {
   1485     NOTREACHED();
   1486     return ERROR_NOINTERFACE;
   1487   }
   1488 
   1489   desired_list->reset();
   1490 
   1491   if (frequency == kFrequencyAny)
   1492     return ERROR_SUCCESS;
   1493 
   1494   // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is
   1495   // needed, then different method of getting BSS (e.g. OID query) will have
   1496   // to be used.
   1497   if (!WlanGetNetworkBssList_function_)
   1498     return ERROR_NOT_SUPPORTED;
   1499 
   1500   DWORD error = ERROR_SUCCESS;
   1501   PWLAN_BSS_LIST bss_list = NULL;
   1502 
   1503   error = WlanGetNetworkBssList_function_(client_,
   1504                                           &interface_guid_,
   1505                                           &ssid,
   1506                                           dot11_BSS_type_infrastructure,
   1507                                           FALSE,
   1508                                           NULL,
   1509                                           &bss_list);
   1510   if (error == ERROR_SUCCESS && NULL != bss_list) {
   1511     unsigned int best_quality = 0u;
   1512     size_t best_index = 0;
   1513     Frequency bss_frequency;
   1514 
   1515     // Go through bss_list and find best quality BSSID with matching frequency.
   1516     for (size_t bss = 0; bss < bss_list->dwNumberOfItems; ++bss) {
   1517       const WLAN_BSS_ENTRY& bss_entry(bss_list->wlanBssEntries[bss]);
   1518       if (bss_entry.dot11Ssid.uSSIDLength != ssid.uSSIDLength ||
   1519           0 != memcmp(bss_entry.dot11Ssid.ucSSID,
   1520                       ssid.ucSSID,
   1521                       bss_entry.dot11Ssid.uSSIDLength))
   1522         continue;
   1523 
   1524       bss_frequency = GetNormalizedFrequency(
   1525           bss_entry.ulChCenterFrequency / 1000);
   1526       if (bss_frequency == frequency &&
   1527           bss_entry.uLinkQuality > best_quality) {
   1528         best_quality = bss_entry.uLinkQuality;
   1529         best_index = bss;
   1530       }
   1531     }
   1532 
   1533     // If any matching BSS were found, prepare the header.
   1534     if (best_quality > 0) {
   1535       const WLAN_BSS_ENTRY& bss_entry(bss_list->wlanBssEntries[best_index]);
   1536       scoped_ptr<DOT11_BSSID_LIST> selected_list(new DOT11_BSSID_LIST);
   1537 
   1538       selected_list->Header.Revision = DOT11_BSSID_LIST_REVISION_1;
   1539       selected_list->Header.Size = sizeof(DOT11_BSSID_LIST);
   1540       selected_list->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
   1541       selected_list->uNumOfEntries = 1;
   1542       selected_list->uTotalNumOfEntries = 1;
   1543       std::copy(bss_entry.dot11Bssid,
   1544                 bss_entry.dot11Bssid+sizeof(bss_entry.dot11Bssid),
   1545                 selected_list->BSSIDs[0]);
   1546       desired_list->swap(selected_list);
   1547       DVLOG(1) << "Quality: " << best_quality << " BSS: "
   1548           << NetworkProperties::MacAddressAsString(bss_entry.dot11Bssid);
   1549     } else {
   1550       error = ERROR_NOT_FOUND;
   1551     }
   1552   }
   1553 
   1554   // Clean up.
   1555   if (bss_list != NULL) {
   1556     WlanFreeMemory_function_(bss_list);
   1557   }
   1558   return error;
   1559 }
   1560 
   1561 Frequency WiFiServiceImpl::GetNormalizedFrequency(int frequency_in_mhz) const {
   1562   if (frequency_in_mhz == 0)
   1563     return kFrequencyAny;
   1564   if (frequency_in_mhz < 3000)
   1565     return kFrequency2400;
   1566   return kFrequency5000;
   1567 }
   1568 
   1569 DWORD WiFiServiceImpl::Connect(const std::string& network_guid,
   1570                                Frequency frequency) {
   1571   if (client_ == NULL) {
   1572     NOTREACHED();
   1573     return ERROR_NOINTERFACE;
   1574   }
   1575 
   1576   DWORD error = ERROR_SUCCESS;
   1577   DOT11_SSID ssid = SSIDFromGUID(network_guid);
   1578   scoped_ptr<DOT11_BSSID_LIST> desired_bss_list;
   1579   error = GetDesiredBssList(ssid, frequency, &desired_bss_list);
   1580   if (error == ERROR_SUCCESS) {
   1581     if (HaveProfile(network_guid)) {
   1582       base::string16 profile_name = ProfileNameFromGUID(network_guid);
   1583       WLAN_CONNECTION_PARAMETERS wlan_params = {
   1584           wlan_connection_mode_profile,
   1585           profile_name.c_str(),
   1586           NULL,
   1587           desired_bss_list.get(),
   1588           dot11_BSS_type_any,
   1589           0};
   1590       error = WlanConnect_function_(
   1591           client_, &interface_guid_, &wlan_params, NULL);
   1592     } else {
   1593       // If network is available, but is not open security, then it cannot be
   1594       // connected without profile, so return 'access denied' error.
   1595       scoped_ptr<base::DictionaryValue> properties (new base::DictionaryValue);
   1596       const base::DictionaryValue* wifi;
   1597       std::string wifi_security;
   1598       std::string error_string;
   1599       GetProperties(network_guid, properties.get(), &error_string);
   1600       if (error_string.empty() &&
   1601           properties->GetDictionary(onc::network_type::kWiFi, &wifi) &&
   1602           wifi->GetString(onc::wifi::kSecurity, &wifi_security) &&
   1603           wifi_security != onc::wifi::kNone) {
   1604         error = ERROR_ACCESS_DENIED;
   1605         LOG(ERROR) << error;
   1606         return error;
   1607       }
   1608       WLAN_CONNECTION_PARAMETERS wlan_params = {
   1609           wlan_connection_mode_discovery_unsecure,
   1610           NULL,
   1611           &ssid,
   1612           desired_bss_list.get(),
   1613           dot11_BSS_type_infrastructure,
   1614           0};
   1615       error = WlanConnect_function_(
   1616           client_, &interface_guid_, &wlan_params, NULL);
   1617     }
   1618   }
   1619 
   1620   return error;
   1621 }
   1622 
   1623 DWORD WiFiServiceImpl::Disconnect() {
   1624   if (client_ == NULL) {
   1625     NOTREACHED();
   1626     return ERROR_NOINTERFACE;
   1627   }
   1628 
   1629   DWORD error = ERROR_SUCCESS;
   1630   error = WlanDisconnect_function_(client_, &interface_guid_, NULL);
   1631   return error;
   1632 }
   1633 
   1634 DWORD WiFiServiceImpl::SaveTempProfile(const std::string& network_guid) {
   1635   if (client_ == NULL) {
   1636     NOTREACHED();
   1637     return ERROR_NOINTERFACE;
   1638   }
   1639 
   1640   DWORD error = ERROR_SUCCESS;
   1641   base::string16 profile_name = ProfileNameFromGUID(network_guid);
   1642   // TODO(mef): WlanSaveTemporaryProfile is not available on XP. If XP support
   1643   // is needed, then different method of saving network profile will have to be
   1644   // used.
   1645   if (WlanSaveTemporaryProfile_function_) {
   1646     error = WlanSaveTemporaryProfile_function_(client_,
   1647                                                &interface_guid_,
   1648                                                profile_name.c_str(),
   1649                                                NULL,
   1650                                                WLAN_PROFILE_USER,
   1651                                                true,
   1652                                                NULL);
   1653   } else {
   1654     error = ERROR_NOT_SUPPORTED;
   1655   }
   1656   return error;
   1657 }
   1658 
   1659 DWORD WiFiServiceImpl::GetProfile(const std::string& network_guid,
   1660                                   bool get_plaintext_key,
   1661                                   std::string* profile_xml) {
   1662   if (client_ == NULL) {
   1663     NOTREACHED();
   1664     return ERROR_NOINTERFACE;
   1665   }
   1666 
   1667   DWORD error = ERROR_SUCCESS;
   1668   base::string16 profile_name = ProfileNameFromGUID(network_guid);
   1669   DWORD flags = get_plaintext_key ? WLAN_PROFILE_GET_PLAINTEXT_KEY : 0;
   1670   LPWSTR str_profile_xml = NULL;
   1671   error = WlanGetProfile_function_(client_,
   1672                                    &interface_guid_,
   1673                                    profile_name.c_str(),
   1674                                    NULL,
   1675                                    &str_profile_xml,
   1676                                    &flags,
   1677                                    NULL);
   1678 
   1679   if (error == ERROR_SUCCESS && str_profile_xml != NULL) {
   1680     *profile_xml = base::UTF16ToUTF8(str_profile_xml);
   1681   }
   1682   // Clean up.
   1683   if (str_profile_xml != NULL) {
   1684     WlanFreeMemory_function_(str_profile_xml);
   1685   }
   1686 
   1687   return error;
   1688 }
   1689 
   1690 DWORD WiFiServiceImpl::SetProfile(bool shared,
   1691                                   const std::string& profile_xml,
   1692                                   bool overwrite) {
   1693   DWORD error_code = ERROR_SUCCESS;
   1694 
   1695   base::string16 profile_xml16(base::UTF8ToUTF16(profile_xml));
   1696   DWORD reason_code = 0u;
   1697 
   1698   error_code = WlanSetProfile_function_(client_,
   1699                                         &interface_guid_,
   1700                                         shared ? 0 : WLAN_PROFILE_USER,
   1701                                         profile_xml16.c_str(),
   1702                                         NULL,
   1703                                         overwrite,
   1704                                         NULL,
   1705                                         &reason_code);
   1706   return error_code;
   1707 }
   1708 
   1709 bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) {
   1710   DWORD error = ERROR_SUCCESS;
   1711   std::string profile_xml;
   1712   return GetProfile(network_guid, false, &profile_xml) == ERROR_SUCCESS;
   1713 }
   1714 
   1715 
   1716 DWORD WiFiServiceImpl::DeleteCreatedProfile(const std::string& network_guid) {
   1717   base::DictionaryValue* created_profile = NULL;
   1718   DWORD error_code = ERROR_SUCCESS;
   1719   // Check, whether this connection is using new created profile, and remove it.
   1720   if (created_profiles_.GetDictionaryWithoutPathExpansion(
   1721       network_guid, &created_profile)) {
   1722     // Connection has failed, so delete it.
   1723     base::string16 profile_name = ProfileNameFromGUID(network_guid);
   1724     error_code = WlanDeleteProfile_function_(client_,
   1725                                               &interface_guid_,
   1726                                               profile_name.c_str(),
   1727                                               NULL);
   1728     created_profiles_.RemoveWithoutPathExpansion(network_guid, NULL);
   1729   }
   1730   return error_code;
   1731 }
   1732 
   1733 std::string WiFiServiceImpl::WpaEncryptionFromEncryptionType(
   1734     EncryptionType encryption_type) const {
   1735   if (encryption_type == kEncryptionTypeTKIP)
   1736     return kEncryptionTKIP;
   1737   return kEncryptionAES;
   1738 }
   1739 
   1740 bool WiFiServiceImpl::AuthEncryptionFromSecurity(
   1741     const std::string& security,
   1742     EncryptionType encryption_type,
   1743     std::string* authentication,
   1744     std::string* encryption,
   1745     std::string* key_type) const {
   1746   if (security == onc::wifi::kNone) {
   1747     *authentication = kAuthenticationOpen;
   1748     *encryption = kEncryptionNone;
   1749   } else if (security == onc::wifi::kWEP_PSK) {
   1750     *authentication = kAuthenticationOpen;
   1751     *encryption = kEncryptionWEP;
   1752     *key_type = kKeyTypeNetwork;
   1753   } else if (security == onc::wifi::kWPA_PSK) {
   1754     *authentication = kAuthenticationWpaPsk;
   1755     *encryption = WpaEncryptionFromEncryptionType(encryption_type);
   1756     *key_type = kKeyTypePassphrase;
   1757   } else if (security == onc::wifi::kWPA2_PSK) {
   1758     *authentication = kAuthenticationWpa2Psk;
   1759     *encryption = WpaEncryptionFromEncryptionType(encryption_type);
   1760     *key_type = kKeyTypePassphrase;
   1761   } else {
   1762     return false;
   1763   }
   1764   return true;
   1765 }
   1766 
   1767 bool WiFiServiceImpl::CreateProfile(
   1768     const NetworkProperties& network_properties,
   1769     EncryptionType encryption_type,
   1770     std::string* profile_xml) {
   1771   // Get authentication and encryption values from security.
   1772   std::string authentication;
   1773   std::string encryption;
   1774   std::string key_type;
   1775   bool valid = AuthEncryptionFromSecurity(network_properties.security,
   1776                                           encryption_type,
   1777                                           &authentication,
   1778                                           &encryption,
   1779                                           &key_type);
   1780   if (!valid)
   1781     return valid;
   1782 
   1783   // Generate profile XML.
   1784   XmlWriter xml_writer;
   1785   xml_writer.StartWriting();
   1786   xml_writer.StartElement("WLANProfile");
   1787   xml_writer.AddAttribute(
   1788       "xmlns",
   1789       "http://www.microsoft.com/networking/WLAN/profile/v1");
   1790   xml_writer.WriteElement("name", network_properties.guid);
   1791   xml_writer.StartElement("SSIDConfig");
   1792   xml_writer.StartElement("SSID");
   1793   xml_writer.WriteElement("name", network_properties.ssid);
   1794   xml_writer.EndElement();  // Ends "SSID" element.
   1795   xml_writer.EndElement();  // Ends "SSIDConfig" element.
   1796   xml_writer.WriteElement("connectionType", "ESS");
   1797   xml_writer.WriteElement("connectionMode", "manual");
   1798   xml_writer.StartElement("MSM");
   1799   xml_writer.StartElement("security");
   1800   xml_writer.StartElement("authEncryption");
   1801   xml_writer.WriteElement("authentication", authentication);
   1802   xml_writer.WriteElement("encryption", encryption);
   1803   xml_writer.WriteElement("useOneX", "false");
   1804   xml_writer.EndElement();  // Ends "authEncryption" element.
   1805   if (!key_type.empty()) {
   1806     xml_writer.StartElement("sharedKey");
   1807     xml_writer.WriteElement("keyType", key_type);
   1808     xml_writer.WriteElement("protected", "false");
   1809     xml_writer.WriteElement("keyMaterial", network_properties.password);
   1810     xml_writer.EndElement();  // Ends "sharedKey" element.
   1811   }
   1812   xml_writer.EndElement();  // Ends "security" element.
   1813   xml_writer.EndElement();  // Ends "MSM" element.
   1814   xml_writer.EndElement();  // Ends "WLANProfile" element.
   1815   xml_writer.StopWriting();
   1816   *profile_xml = xml_writer.GetWrittenString();
   1817 
   1818   return true;
   1819 }
   1820 
   1821 void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList& networks) {
   1822   if (network_list_changed_observer_.is_null())
   1823     return;
   1824 
   1825   NetworkGuidList current_networks;
   1826   for (NetworkList::const_iterator it = networks.begin();
   1827        it != networks.end();
   1828        ++it) {
   1829     current_networks.push_back(it->guid);
   1830   }
   1831 
   1832   message_loop_proxy_->PostTask(
   1833       FROM_HERE,
   1834       base::Bind(network_list_changed_observer_, current_networks));
   1835 }
   1836 
   1837 void WiFiServiceImpl::NotifyNetworkChanged(const std::string& network_guid) {
   1838   if (enable_notify_network_changed_ && !networks_changed_observer_.is_null()) {
   1839     DVLOG(1) << "NotifyNetworkChanged: " << network_guid;
   1840     NetworkGuidList changed_networks(1, network_guid);
   1841     message_loop_proxy_->PostTask(
   1842         FROM_HERE,
   1843         base::Bind(networks_changed_observer_, changed_networks));
   1844   }
   1845 }
   1846 
   1847 WiFiService* WiFiService::Create() { return new WiFiServiceImpl(); }
   1848 
   1849 }  // namespace wifi
   1850