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"
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"
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\\"
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
)(
57 CONST GUID
*pInterfaceGuid
,
58 CONST PWLAN_CONNECTION_PARAMETERS pConnectionParameters
,
61 typedef DWORD (WINAPI
* WlanCloseHandleFunction
)(
65 typedef DWORD (WINAPI
* WlanDisconnectFunction
)(
67 CONST GUID
*pInterfaceGuid
,
70 typedef DWORD (WINAPI
* WlanEnumInterfacesFunction
)(
73 PWLAN_INTERFACE_INFO_LIST
*ppInterfaceList
);
75 typedef VOID (WINAPI
* WlanFreeMemoryFunction
)(
78 typedef DWORD (WINAPI
* WlanGetAvailableNetworkListFunction
)(
80 CONST GUID
*pInterfaceGuid
,
83 PWLAN_AVAILABLE_NETWORK_LIST
*ppAvailableNetworkList
);
85 typedef DWORD (WINAPI
* WlanGetNetworkBssListFunction
)(
87 const GUID
* pInterfaceGuid
,
88 const PDOT11_SSID pDot11Ssid
,
89 DOT11_BSS_TYPE dot11BssType
,
90 BOOL bSecurityEnabled
,
92 PWLAN_BSS_LIST
* ppWlanBssList
);
94 typedef DWORD (WINAPI
* WlanGetProfileFunction
)(
96 CONST GUID
*pInterfaceGuid
,
97 LPCWSTR strProfileName
,
99 LPWSTR
*pstrProfileXml
,
101 DWORD
*pdwGrantedAccess
);
103 typedef DWORD (WINAPI
* WlanOpenHandleFunction
)(
104 DWORD dwClientVersion
,
106 PDWORD pdwNegotiatedVersion
,
107 PHANDLE phClientHandle
);
109 typedef DWORD (WINAPI
* WlanQueryInterfaceFunction
)(
110 HANDLE hClientHandle
,
111 const GUID
*pInterfaceGuid
,
112 WLAN_INTF_OPCODE OpCode
,
116 PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType
);
118 typedef DWORD (WINAPI
* WlanRegisterNotificationFunction
)(
119 HANDLE hClientHandle
,
121 BOOL bIgnoreDuplicate
,
122 WLAN_NOTIFICATION_CALLBACK funcCallback
,
123 PVOID pCallbackContext
,
125 PDWORD pdwPrevNotifSource
);
127 typedef DWORD (WINAPI
* WlanSaveTemporaryProfileFunction
)(
128 HANDLE hClientHandle
,
129 CONST GUID
* pInterfaceGuid
,
130 LPCWSTR strProfileName
,
131 LPCWSTR strAllUserProfileSecurity
,
136 typedef DWORD (WINAPI
* WlanScanFunction
)(
137 HANDLE hClientHandle
,
138 CONST GUID
*pInterfaceGuid
,
139 CONST PDOT11_SSID pDot11Ssid
,
140 CONST PWLAN_RAW_DATA pIeData
,
143 typedef DWORD (WINAPI
* WlanSetProfileFunction
)(
144 HANDLE hClientHandle
,
145 const GUID
*pInterfaceGuid
,
147 LPCWSTR strProfileXml
,
148 LPCWSTR strAllUserProfileSecurity
,
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";
169 // Implementation of WiFiService for Windows.
170 class WiFiServiceImpl
: public WiFiService
{
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
{}
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
,
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|
243 void WaitForNetworkConnect(const std::string
& network_guid
, int attempt
);
245 // Check |error_code| and if is not |ERROR_SUCCESS|, then store |error_name|
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|
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
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
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|
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.
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
,
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
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.
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
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
),
453 enable_notify_network_changed_(true) {}
455 WiFiServiceImpl::~WiFiServiceImpl() { UnInitialize(); }
457 void WiFiServiceImpl::Initialize(
458 scoped_refptr
<base::SequencedTaskRunner
> task_runner
) {
460 task_runner_
.swap(task_runner
);
461 // Restore NwCategoryWizard in case if we crashed during connect.
462 RestoreNwCategoryWizard();
466 void WiFiServiceImpl::UnInitialize() {
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());
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
;
518 connect_properties_
.SetWithoutPathExpansion(network_guid
,
519 properties
.release());
522 void WiFiServiceImpl::CreateNetwork(
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
))
531 WiFiService::NetworkProperties network_properties
;
532 if (!network_properties
.UpdateFromValue(*properties
)) {
533 CheckError(ERROR_INVALID_DATA
, kWiFiServiceError
, error
);
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
);
544 base::string16
profile_xml16(base::UTF8ToUTF16(profile_xml
));
545 DWORD reason_code
= 0u;
547 error_code
= WlanSetProfile_function_(client_
,
549 shared
? 0 : WLAN_PROFILE_USER
,
550 profile_xml16
.c_str(),
555 if (CheckError(error_code
, kWiFiServiceError
, error
)) {
556 DVLOG(0) << profile_xml
;
557 DVLOG(0) << "SetProfile Reason Code:" << reason_code
;
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
) {
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();
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);
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
);
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
))
657 std::string profile_xml
;
658 error_code
= GetProfile(network_guid
, true, &profile_xml
);
659 if (CheckError(error_code
, kWiFiServiceError
, error
))
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
;
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
;
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
,
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
)
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(
731 base::Bind(&WiFiServiceImpl::NotifyNetworkChanged
,
732 base::Unretained(this),
733 GUIDFromSSID(wlan_connection_data
->dot11Ssid
)));
736 case wlan_notification_acm_scan_complete
:
737 message_loop_proxy_
->PostTask(
739 base::Bind(&WiFiServiceImpl::OnNetworkScanCompleteOnMainThread
,
740 base::Unretained(this)));
745 void WiFiServiceImpl::OnNetworkScanCompleteOnMainThread() {
746 NetworkList networks
;
747 // Get current list of visible networks and notify that network list has
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
,
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 "
762 enable_notify_network_changed_
= true;
763 RestoreNwCategoryWizard();
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.
774 // Restore previously suppressed notifications.
775 enable_notify_network_changed_
= true;
776 RestoreNwCategoryWizard();
777 NotifyNetworkChanged(network_guid
);
779 // Continue waiting for network connection state change.
780 task_runner_
->PostDelayedTask(
782 base::Bind(&WiFiServiceImpl::WaitForNetworkConnect
,
783 base::Unretained(this),
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
;
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();
806 if (it
->guid
== network_guid
)
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
;
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.
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(),
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
));
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
)
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
;
946 WlanRegisterNotification_function_(client_
,
947 WLAN_NOTIFICATION_SOURCE_ALL
,
949 OnWlanNotificationCallback
,
954 error
= ERROR_NOINTERFACE
;
958 if (interface_list
!= NULL
)
959 WlanFreeMemory_function_(interface_list
);
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
);
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;
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
) {
994 interface_info
->Adapter
[adapter
].Name
, guid_string
, false)) {
995 *adapter_index_map
= interface_info
->Adapter
[adapter
];
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
)) {
1013 error
= nw_category_wizard
.ReadValueDW(kNwCategoryWizardRegValue
,
1015 if (error
== ERROR_SUCCESS
) {
1016 error
= nw_category_wizard
.WriteValue(kNwCategoryWizardSavedRegValue
,
1020 // Mark that temporary value has to be deleted.
1021 error
= nw_category_wizard
.WriteValue(kNwCategoryWizardDeleteRegValue
,
1025 // Disable network location wizard.
1026 error
= nw_category_wizard
.WriteValue(kNwCategoryWizardRegValue
,
1027 static_cast<DWORD
>(0));
1033 DWORD
WiFiServiceImpl::RestoreNwCategoryWizard() {
1034 base::win::RegKey nw_category_wizard
;
1035 DWORD error
= nw_category_wizard
.Open(HKEY_CURRENT_USER
,
1036 kNwCategoryWizardRegKey
,
1038 if (error
== ERROR_SUCCESS
) {
1039 // Restore saved value if present.
1040 if (nw_category_wizard
.HasValue(kNwCategoryWizardSavedRegValue
)) {
1042 error
= nw_category_wizard
.ReadValueDW(kNwCategoryWizardSavedRegValue
,
1044 if (error
== ERROR_SUCCESS
) {
1045 error
= nw_category_wizard
.WriteValue(kNwCategoryWizardRegValue
,
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
);
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
);
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
;
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(),
1104 std::string
WiFiServiceImpl::SecurityFromDot11AuthAlg(
1105 DOT11_AUTH_ALGORITHM alg
) const {
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
;
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
;
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
) {
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_(
1167 WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES
,
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
1179 error
= WlanGetNetworkBssList_function_(client_
,
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
],
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
;
1206 network_list
->push_back(network_properties
);
1208 network_guids
.insert(network_properties
.guid
);
1214 if (available_network_list
!= NULL
) {
1215 WlanFreeMemory_function_(available_network_list
);
1217 if (bss_list
!= NULL
) {
1218 WlanFreeMemory_function_(bss_list
);
1223 // Find currently connected network.
1224 DWORD
WiFiServiceImpl::FindConnectedNetwork(
1225 std::string
* connected_network_guid
) {
1226 if (client_
== NULL
) {
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
);
1247 if (available_network_list
!= NULL
) {
1248 WlanFreeMemory_function_(available_network_list
);
1254 WiFiService::Frequency
WiFiServiceImpl::GetConnectedFrequency(
1255 const std::string
& network_guid
) {
1256 if (client_
== NULL
) {
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
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_(
1275 wlan_intf_opcode_current_connection
,
1278 reinterpret_cast<PVOID
*>(&wlan_connection_attributes
),
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_
,
1290 &connected_wlan
.dot11Ssid
,
1291 connected_wlan
.dot11BssType
,
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);
1312 if (wlan_connection_attributes
!= NULL
) {
1313 WlanFreeMemory_function_(wlan_connection_attributes
);
1316 if (bss_list
!= NULL
) {
1317 WlanFreeMemory_function_(bss_list
);
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
;
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(
1340 Frequency frequency
,
1341 scoped_ptr
<DOT11_BSSID_LIST
>* desired_list
) {
1342 if (client_
== NULL
) {
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
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_
,
1364 dot11_BSS_type_infrastructure
,
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
,
1379 bss_entry
.dot11Ssid
.uSSIDLength
))
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
;
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
);
1408 error
= ERROR_NOT_FOUND
;
1413 if (bss_list
!= NULL
) {
1414 WlanFreeMemory_function_(bss_list
);
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
) {
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(),
1446 desired_bss_list
.get(),
1449 error
= WlanConnect_function_(
1450 client_
, &interface_guid_
, &wlan_params
, NULL
);
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
1455 WLAN_CONNECTION_PARAMETERS wlan_params
= {
1456 wlan_connection_mode_discovery_unsecure
,
1459 desired_bss_list
.get(),
1460 dot11_BSS_type_infrastructure
,
1462 error
= WlanConnect_function_(
1463 client_
, &interface_guid_
, &wlan_params
, NULL
);
1470 DWORD
WiFiServiceImpl::Disconnect() {
1471 if (client_
== NULL
) {
1473 return ERROR_NOINTERFACE
;
1476 DWORD error
= ERROR_SUCCESS
;
1477 error
= WlanDisconnect_function_(client_
, &interface_guid_
, NULL
);
1481 DWORD
WiFiServiceImpl::SaveTempProfile(const std::string
& network_guid
) {
1482 if (client_
== NULL
) {
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
1492 if (WlanSaveTemporaryProfile_function_
) {
1493 error
= WlanSaveTemporaryProfile_function_(client_
,
1495 profile_name
.c_str(),
1501 error
= ERROR_NOT_SUPPORTED
;
1506 DWORD
WiFiServiceImpl::GetProfile(const std::string
& network_guid
,
1507 bool get_plaintext_key
,
1508 std::string
* profile_xml
) {
1509 if (client_
== NULL
) {
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_
,
1520 profile_name
.c_str(),
1526 if (error
== ERROR_SUCCESS
&& str_profile_xml
!= NULL
) {
1527 *profile_xml
= base::UTF16ToUTF8(str_profile_xml
);
1530 if (str_profile_xml
!= NULL
) {
1531 WlanFreeMemory_function_(str_profile_xml
);
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
;
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
,
1587 // Generate profile XML.
1588 XmlWriter xml_writer
;
1589 xml_writer
.StartWriting();
1590 xml_writer
.StartElement("WLANProfile");
1591 xml_writer
.AddAttribute(
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();
1625 void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList
& networks
) {
1626 if (network_list_changed_observer_
.is_null())
1629 NetworkGuidList current_networks
;
1630 for (NetworkList::const_iterator it
= networks
.begin();
1631 it
!= networks
.end();
1633 current_networks
.push_back(it
->guid
);
1636 message_loop_proxy_
->PostTask(
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(
1647 base::Bind(networks_changed_observer_
, changed_networks
));
1651 WiFiService
* WiFiService::Create() { return new WiFiServiceImpl(); }