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