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