OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/wifi/wifi_service.h" | |
6 | |
7 #include <iphlpapi.h> | |
8 #include <objbase.h> | |
9 #include <wlanapi.h> | |
10 | |
11 #include <set> | |
12 | |
13 #include "base/base_paths_win.h" | |
14 #include "base/bind.h" | |
15 #include "base/files/file_path.h" | |
16 #include "base/memory/ref_counted.h" | |
17 #include "base/message_loop/message_loop.h" | |
18 #include "base/path_service.h" | |
19 #include "base/strings/string16.h" | |
20 #include "base/strings/string_util.h" | |
21 #include "base/strings/utf_string_conversions.h" | |
22 #include "base/win/registry.h" | |
23 #include "components/onc/onc_constants.h" | |
24 | |
25 namespace { | |
26 const char kWiFiServiceError[] = "Error.WiFiService"; | |
27 const wchar_t kNwCategoryWizardRegKey[] = | |
28 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Network\\" | |
29 L"NwCategoryWizard"; | |
30 const wchar_t kNwCategoryWizardRegValue[] = L"Show"; | |
31 const wchar_t kNwCategoryWizardSavedRegValue[] = L"ShowSaved"; | |
32 const wchar_t kNwCategoryWizardDeleteRegValue[] = L"ShowDelete"; | |
33 const wchar_t kWlanApiDll[] = L"wlanapi.dll"; | |
34 | |
35 // WlanApi function names | |
36 const char kWlanConnect[] = "WlanConnect"; | |
37 const char kWlanCloseHandle[] = "WlanCloseHandle"; | |
38 const char kWlanDisconnect[] = "WlanDisconnect"; | |
39 const char kWlanEnumInterfaces[] = "WlanEnumInterfaces"; | |
40 const char kWlanFreeMemory[] = "WlanFreeMemory"; | |
41 const char kWlanGetAvailableNetworkList[] = "WlanGetAvailableNetworkList"; | |
42 const char kWlanGetNetworkBssList[] = "WlanGetNetworkBssList"; | |
43 const char kWlanGetProfile[] = "WlanGetProfile"; | |
44 const char kWlanOpenHandle[] = "WlanOpenHandle"; | |
45 const char kWlanRegisterNotification[] = "WlanRegisterNotification"; | |
46 const char kWlanSaveTemporaryProfile[] = "WlanSaveTemporaryProfile"; | |
47 const char kWlanScan[] = "WlanScan"; | |
48 | |
49 // WlanApi function definitions | |
50 typedef DWORD (WINAPI* WlanConnectFunction)( | |
51 HANDLE hClientHandle, | |
52 CONST GUID *pInterfaceGuid, | |
53 CONST PWLAN_CONNECTION_PARAMETERS pConnectionParameters, | |
54 PVOID pReserved); | |
55 | |
56 typedef DWORD (WINAPI* WlanCloseHandleFunction)( | |
57 HANDLE hClientHandle, | |
58 PVOID pReserved); | |
59 | |
60 typedef DWORD (WINAPI* WlanDisconnectFunction)( | |
61 HANDLE hClientHandle, | |
62 CONST GUID *pInterfaceGuid, | |
63 PVOID pReserved); | |
64 | |
65 typedef DWORD (WINAPI* WlanEnumInterfacesFunction)( | |
66 HANDLE hClientHandle, | |
67 PVOID pReserved, | |
68 PWLAN_INTERFACE_INFO_LIST *ppInterfaceList); | |
69 | |
70 typedef VOID (WINAPI* WlanFreeMemoryFunction)( | |
71 _In_ PVOID pMemory); | |
72 | |
73 typedef DWORD (WINAPI* WlanGetAvailableNetworkListFunction)( | |
74 HANDLE hClientHandle, | |
75 CONST GUID *pInterfaceGuid, | |
76 DWORD dwFlags, | |
77 PVOID pReserved, | |
78 PWLAN_AVAILABLE_NETWORK_LIST *ppAvailableNetworkList); | |
79 | |
80 typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)( | |
81 HANDLE hClientHandle, | |
82 const GUID* pInterfaceGuid, | |
83 const PDOT11_SSID pDot11Ssid, | |
84 DOT11_BSS_TYPE dot11BssType, | |
85 BOOL bSecurityEnabled, | |
86 PVOID pReserved, | |
87 PWLAN_BSS_LIST* ppWlanBssList); | |
88 | |
89 typedef DWORD (WINAPI* WlanGetProfileFunction)( | |
90 HANDLE hClientHandle, | |
91 CONST GUID *pInterfaceGuid, | |
92 LPCWSTR strProfileName, | |
93 PVOID pReserved, | |
94 LPWSTR *pstrProfileXml, | |
95 DWORD *pdwFlags, | |
96 DWORD *pdwGrantedAccess); | |
97 | |
98 typedef DWORD (WINAPI* WlanOpenHandleFunction)( | |
99 DWORD dwClientVersion, | |
100 PVOID pReserved, | |
101 PDWORD pdwNegotiatedVersion, | |
102 PHANDLE phClientHandle); | |
103 | |
104 typedef DWORD (WINAPI* WlanRegisterNotificationFunction)( | |
105 HANDLE hClientHandle, | |
106 DWORD dwNotifSource, | |
107 BOOL bIgnoreDuplicate, | |
108 WLAN_NOTIFICATION_CALLBACK funcCallback, | |
109 PVOID pCallbackContext, | |
110 PVOID pReserved, | |
111 PDWORD pdwPrevNotifSource); | |
112 | |
113 typedef DWORD (WINAPI* WlanSaveTemporaryProfileFunction)( | |
114 HANDLE hClientHandle, | |
115 CONST GUID* pInterfaceGuid, | |
116 LPCWSTR strProfileName, | |
117 LPCWSTR strAllUserProfileSecurity, | |
118 DWORD dwFlags, | |
119 BOOL bOverWrite, | |
120 PVOID pReserved); | |
121 | |
122 typedef DWORD (WINAPI* WlanScanFunction)( | |
123 HANDLE hClientHandle, | |
124 CONST GUID *pInterfaceGuid, | |
125 CONST PDOT11_SSID pDot11Ssid, | |
126 CONST PWLAN_RAW_DATA pIeData, | |
127 PVOID pReserved); | |
128 | |
129 } // namespace | |
130 | |
131 namespace wifi { | |
132 | |
133 // Implementation of WiFiService for Windows. | |
134 class WiFiServiceImpl : public WiFiService, base::NonThreadSafe { | |
Jói
2013/11/20 11:08:40
A minor nit on naming; it's inconsistent to use Wi
| |
135 public: | |
136 WiFiServiceImpl(); | |
137 virtual ~WiFiServiceImpl(); | |
138 | |
139 // WiFiService interface implementation. | |
140 virtual void Initialize( | |
141 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE; | |
142 | |
143 virtual void UnInitialize() OVERRIDE; | |
144 | |
145 // Get Properties of network identified by |network_guid|. Populates | |
146 // |properties| on success, |error| on failure. | |
147 virtual void GetProperties(const std::string& network_guid, | |
148 DictionaryValue* properties, | |
149 std::string* error) OVERRIDE; | |
150 | |
151 // Set Properties of network identified by |network_guid|. Populates |error| | |
152 // on failure. | |
153 virtual void SetProperties(const std::string& network_guid, | |
154 scoped_ptr<base::DictionaryValue> properties, | |
155 std::string* error) OVERRIDE; | |
156 | |
157 // Get list of visible networks. Populates |network_list| on success. | |
158 virtual void GetVisibleNetworks(ListValue* network_list) OVERRIDE; | |
159 | |
160 // Request network scan. Send |NetworkListChanged| event on completion. | |
161 virtual void RequestNetworkScan() OVERRIDE; | |
162 | |
163 // Start connect to network identified by |network_guid|. Populates |error| | |
164 // on failure. | |
165 virtual void StartConnect(const std::string& network_guid, | |
166 std::string* error) OVERRIDE; | |
167 | |
168 // Start disconnect from network identified by |network_guid|. Populates | |
169 // |error| on failure. | |
170 virtual void StartDisconnect(const std::string& network_guid, | |
171 std::string* error) OVERRIDE; | |
172 | |
173 // Set observers to run when |NetworksChanged| and |NetworksListChanged| | |
174 // events needs to be sent. Notifications are posted on |message_loop_proxy|. | |
175 virtual void SetEventObservers( | |
176 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, | |
177 const NetworkGuidListCallback& networks_changed_observer, | |
178 const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE; | |
179 | |
180 private: | |
181 // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification | |
182 // on WiFiServiceImpl passed back as |context|. | |
183 static void __stdcall OnWlanNotificationCallback( | |
184 PWLAN_NOTIFICATION_DATA wlan_notification_data, | |
185 PVOID context); | |
186 | |
187 // Callback for Windows WLAN_NOTIFICATION. Called on random thread from | |
188 // OnWlanNotificationCallback. Handles network connectivity and scan complete | |
189 // notification and posts tasks to main thread. | |
190 void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data); | |
191 | |
192 // Handles NetworkScanComplete notification on main thread. Sends | |
193 // |NetworkListChanged| event with new list of visible networks. | |
194 void OnNetworkScanCompleteOnMainThread(); | |
195 | |
196 // Wait up to |kMaxAttempts| with |kAttemptDelayMs| delay for connection | |
197 // to network with |network_guid|. Reset DHCP and Notify that |NetworkChanged| | |
198 // upon success. | |
199 void WaitForNetworkConnect(const std::string& network_guid, int attempt); | |
200 | |
201 // Check |error_code| and if is not |ERROR_SUCCESS|, then store |error_name| | |
202 // into |error|. | |
203 bool CheckError(DWORD error_code, | |
204 const std::string& error_name, | |
205 std::string* error) const; | |
206 | |
207 // Return |iterator| to network identified by |network_guid| in |networks| | |
208 // list. | |
209 NetworkList::iterator FindNetwork(NetworkList& networks, | |
210 const std::string& network_guid); | |
211 | |
212 // Save currently connected network profile and return its | |
213 // |connected_network_guid|, so it can be re-connected later. | |
214 DWORD SaveCurrentConnectedNetwork(std::string* connected_network_guid); | |
215 | |
216 // Sort networks, so connected/connecting is up front, then by type: | |
217 // Ethernet, WiFi, Cellular, VPN | |
218 static void SortNetworks(NetworkList* networks); | |
219 | |
220 // Open a WLAN client handle, register for WLAN notifications. | |
221 DWORD OpenClientHandle(); | |
222 | |
223 // Reset DHCP on wireless network to work around an issue when Windows | |
224 // takes forever to connect to the network, e.g. after Chromecast | |
225 // device reset. | |
226 DWORD ResetDHCP(); | |
227 | |
228 // Find |adapter_index_map| by |interface_guid| for DHCP reset. | |
229 DWORD FindAdapterIndexMapByGUID(const GUID& interface_guid, | |
230 IP_ADAPTER_INDEX_MAP* adapter_index_map); | |
231 | |
232 // Avoid the network location wizard to pop up when network is connected. | |
233 // Preserve current value in |saved_nw_category_wizard_|. | |
234 DWORD DisableNwCategoryWizard(); | |
235 | |
236 // Restore network location wizard to value saved by DisableNwCategoryWizard. | |
237 DWORD RestoreNwCategoryWizard(); | |
238 | |
239 // Ensure that |client_| handle is initialized. | |
240 DWORD EnsureInitialized(); | |
241 | |
242 // Close |client_| handle if it is open. | |
243 DWORD CloseClientHandle(); | |
244 | |
245 // Get |profile_name| from unique |network_guid|. | |
246 base::string16 ProfileNameFromGUID(const std::string& network_guid) const { | |
247 return base::UTF8ToUTF16(network_guid); | |
248 } | |
249 | |
250 // Get |dot11_ssid| from unique |network_guid|. | |
251 DOT11_SSID SSIDFromGUID(const std::string& network_guid) const; | |
252 | |
253 // Get unique |network_guid| string based on |dot11_ssid|. | |
254 std::string GUIDFromSSID(const DOT11_SSID& dot11_ssid) const { | |
255 return std::string(reinterpret_cast<const char*>(dot11_ssid.ucSSID), | |
256 dot11_ssid.uSSIDLength); | |
257 } | |
258 | |
259 // Get network |ssid| string based on |wlan|. | |
260 std::string SSIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const { | |
261 return GUIDFromSSID(wlan.dot11Ssid); | |
262 } | |
263 | |
264 // Get unique |network_guid| string based on |wlan|. | |
265 std::string GUIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const { | |
266 return SSIDFromWLAN(wlan); | |
267 } | |
268 | |
269 // Deduce |onc::wifi| security from |alg|. | |
270 std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const; | |
271 | |
272 // Populate |properties| based on |wlan| and its corresponding bss info from | |
273 // |wlan_bss_list|. | |
274 void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan, | |
275 const WLAN_BSS_LIST& wlan_bss_list, | |
276 NetworkProperties* properties); | |
277 | |
278 // Get the list of visible wireless networks. | |
279 DWORD GetVisibleNetworkList(NetworkList* network_list); | |
280 | |
281 // Find currently connected network if any. Populate |connected_network_guid| | |
282 // on success. | |
283 DWORD FindConnectedNetwork(std::string* connected_network_guid); | |
284 | |
285 // Connect to network |network_guid| using previosly stored profile if exists, | |
286 // or just network sid. If |frequency| is not |kFrequencyUnknown| then | |
287 // connects only to BSS which uses that frequency and returns | |
288 // |ERROR_NOT_FOUND| if such BSS cannot be found. | |
289 DWORD Connect(const std::string& network_guid, Frequency frequency); | |
290 | |
291 // Disconnect from currently connected network if any. | |
292 DWORD Disconnect(); | |
293 | |
294 // Get DOT11_BSSID_LIST of desired BSSIDs to connect to |ssid| network on | |
295 // given |frequency|. | |
296 DWORD GetDesiredBssList(DOT11_SSID& ssid, | |
297 Frequency frequency, | |
298 scoped_ptr<DOT11_BSSID_LIST>* desired_list); | |
299 | |
300 // Save temporary wireless profile for |network_guid|. | |
301 DWORD SaveTempProfile(const std::string& network_guid); | |
302 | |
303 // Get previously stored |profile_xml| for |network_guid|. | |
304 DWORD GetProfile(const std::string& network_guid, std::string* profile_xml); | |
305 | |
306 // Return true if there is previously stored profile xml for |network_guid|. | |
307 bool HaveProfile(const std::string& network_guid); | |
308 | |
309 // Notify |network_list_changed_observer_| that list of visible networks has | |
310 // changed to |networks|. | |
311 void NotifyNetworkListChanged(const NetworkList& networks); | |
312 | |
313 // Notify |networks_changed_observer_| that network |network_guid| status has | |
314 // changed. | |
315 void NotifyNetworkChanged(const std::string& network_guid); | |
316 | |
317 // Load WlanApi.dll from SystemDirectory and get Api function pointers. | |
318 DWORD LoadWlanLibrary(); | |
319 // Instance of WlanApi.dll. | |
320 HINSTANCE wlan_api_library_; | |
321 // WlanApi function pointers | |
322 WlanConnectFunction WlanConnect_function_; | |
323 WlanCloseHandleFunction WlanCloseHandle_function_; | |
324 WlanDisconnectFunction WlanDisconnect_function_; | |
325 WlanEnumInterfacesFunction WlanEnumInterfaces_function_; | |
326 WlanFreeMemoryFunction WlanFreeMemory_function_; | |
327 WlanGetAvailableNetworkListFunction WlanGetAvailableNetworkList_function_; | |
328 // WlanGetNetworkBssList function may not be avaiable on Windows XP. | |
329 WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_; | |
330 WlanGetProfileFunction WlanGetProfile_function_; | |
331 WlanOpenHandleFunction WlanOpenHandle_function_; | |
332 WlanRegisterNotificationFunction WlanRegisterNotification_function_; | |
333 WlanScanFunction WlanScan_function_; | |
334 // WlanSaveTemporaryProfile function may not be avaiable on Windows XP. | |
335 WlanSaveTemporaryProfileFunction WlanSaveTemporaryProfile_function_; | |
336 | |
337 // WLAN service handle. | |
338 HANDLE client_; | |
339 // GUID of the currently connected interface, if any, otherwise the GUID of | |
340 // one of the WLAN interfaces. | |
341 GUID interface_guid_; | |
342 // Preserved WLAN profile xml. | |
343 std::map<std::string, std::string> saved_profiles_xml_; | |
344 // Observer to get notified when network(s) have changed (e.g. connect). | |
345 NetworkGuidListCallback networks_changed_observer_; | |
346 // Observer to get notified when network list has changed (scan complete). | |
347 NetworkGuidListCallback network_list_changed_observer_; | |
348 // Saved value of network location wizard show value. | |
349 scoped_ptr<DWORD> saved_nw_category_wizard_; | |
350 // MessageLoopProxy to post events on UI thread. | |
351 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; | |
352 // Task runner for worker tasks. | |
353 scoped_refptr<base::SequencedTaskRunner> task_runner_; | |
354 // If |false|, then |networks_changed_observer_| is not notified. | |
355 bool enable_notify_network_changed_; | |
356 // Number of attempts to check that network has connected successfully. | |
357 static const int kMaxAttempts = 100; | |
358 // Delay between attempts to check that network has connected successfully. | |
359 static const int kAttemptDelayMs = 100; | |
360 DISALLOW_COPY_AND_ASSIGN(WiFiServiceImpl); | |
361 }; | |
362 | |
363 WiFiServiceImpl::WiFiServiceImpl() | |
364 : wlan_api_library_(NULL), | |
365 WlanConnect_function_(NULL), | |
366 WlanCloseHandle_function_(NULL), | |
367 WlanDisconnect_function_(NULL), | |
368 WlanEnumInterfaces_function_(NULL), | |
369 WlanFreeMemory_function_(NULL), | |
370 WlanGetAvailableNetworkList_function_(NULL), | |
371 WlanGetNetworkBssList_function_(NULL), | |
372 WlanGetProfile_function_(NULL), | |
373 WlanOpenHandle_function_(NULL), | |
374 WlanRegisterNotification_function_(NULL), | |
375 WlanSaveTemporaryProfile_function_(NULL), | |
376 WlanScan_function_(NULL), | |
377 client_(NULL), | |
378 enable_notify_network_changed_(true) {} | |
379 | |
380 WiFiServiceImpl::~WiFiServiceImpl() { UnInitialize(); } | |
381 | |
382 void WiFiServiceImpl::Initialize( | |
383 scoped_refptr<base::SequencedTaskRunner> task_runner) { | |
384 DCHECK(!client_); | |
385 task_runner_.swap(task_runner); | |
386 // Restore NwCategoryWizard in case if we crashed during connect. | |
387 RestoreNwCategoryWizard(); | |
388 OpenClientHandle(); | |
389 } | |
390 | |
391 void WiFiServiceImpl::UnInitialize() { | |
392 CloseClientHandle(); | |
393 } | |
394 | |
395 void WiFiServiceImpl::GetProperties(const std::string& network_guid, | |
396 DictionaryValue* properties, | |
397 std::string* error) { | |
398 DWORD error_code = EnsureInitialized(); | |
399 if (error_code == ERROR_SUCCESS) { | |
400 NetworkList network_list; | |
401 error_code = GetVisibleNetworkList(&network_list); | |
402 if (error_code == ERROR_SUCCESS && !network_list.empty()) { | |
403 NetworkList::const_iterator it = FindNetwork(network_list, network_guid); | |
404 if (it != network_list.end()) { | |
405 DLOG(INFO) << "Get Properties: " << network_guid << ":" | |
406 << it->connection_state; | |
407 properties->Swap(it->ToValue(false).get()); | |
408 return; | |
409 } else { | |
410 error_code = ERROR_NOT_FOUND; | |
411 } | |
412 } | |
413 } | |
414 | |
415 CheckError(error_code, kWiFiServiceError, error); | |
416 } | |
417 | |
418 void WiFiServiceImpl::SetProperties( | |
419 const std::string& network_guid, | |
420 scoped_ptr<base::DictionaryValue> properties, | |
421 std::string* error) { | |
422 // This method is not implemented in first version as it is not used by | |
423 // Google Cast extension. | |
424 CheckError(ERROR_CALL_NOT_IMPLEMENTED, kWiFiServiceError, error); | |
425 } | |
426 | |
427 void WiFiServiceImpl::GetVisibleNetworks(ListValue* network_list) { | |
428 DWORD error = EnsureInitialized(); | |
429 | |
430 if (error == ERROR_SUCCESS) { | |
431 NetworkList networks; | |
432 error = GetVisibleNetworkList(&networks); | |
433 if (error == ERROR_SUCCESS && !networks.empty()) { | |
434 SortNetworks(&networks); | |
435 for (WiFiService::NetworkList::const_iterator it = networks.begin(); | |
436 it != networks.end(); | |
437 ++it) { | |
438 scoped_ptr<DictionaryValue> network(it->ToValue(true)); | |
439 network_list->Append(network.release()); | |
440 } | |
441 } | |
442 } | |
443 } | |
444 | |
445 void WiFiServiceImpl::RequestNetworkScan() { | |
446 DWORD error = EnsureInitialized(); | |
447 if (error == ERROR_SUCCESS) { | |
448 WlanScan_function_(client_, &interface_guid_, NULL, NULL, NULL); | |
449 } | |
450 } | |
451 | |
452 void WiFiServiceImpl::StartConnect(const std::string& network_guid, | |
453 std::string* error) { | |
454 DLOG(INFO) << "Start Connect: " << network_guid; | |
455 DWORD error_code = EnsureInitialized(); | |
456 if (error_code == ERROR_SUCCESS) { | |
457 std::string connected_network_guid; | |
458 error_code = SaveCurrentConnectedNetwork(&connected_network_guid); | |
459 if (error_code == ERROR_SUCCESS) { | |
460 Frequency frequency = kFrequencyAny; | |
461 // Connect only if network |network_guid| is not connected already. | |
462 if (network_guid != connected_network_guid) | |
463 error_code = Connect(network_guid, frequency); | |
464 if (error_code == ERROR_SUCCESS) { | |
465 // Notify that previously connected network has changed. | |
466 NotifyNetworkChanged(connected_network_guid); | |
467 // Start waiting for network connection state change. | |
468 if (!networks_changed_observer_.is_null()) { | |
469 DisableNwCategoryWizard(); | |
470 // Disable automatic network change notifications as they get fired | |
471 // when network is just connected, but not yet accessible (doesn't | |
472 // have valid IP address). | |
473 enable_notify_network_changed_ = false; | |
474 WaitForNetworkConnect(network_guid, 0); | |
475 return; | |
476 } | |
477 } | |
478 } | |
479 } | |
480 CheckError(error_code, kWiFiServiceError, error); | |
481 } | |
482 | |
483 void WiFiServiceImpl::StartDisconnect(const std::string& network_guid, | |
484 std::string* error) { | |
485 DLOG(INFO) << "Start Disconnect: " << network_guid; | |
486 DWORD error_code = EnsureInitialized(); | |
487 if (error_code == ERROR_SUCCESS) { | |
488 std::string connected_network_guid; | |
489 error_code = SaveCurrentConnectedNetwork(&connected_network_guid); | |
490 if (error_code == ERROR_SUCCESS && network_guid == connected_network_guid) { | |
491 error_code = Disconnect(); | |
492 if (error_code == ERROR_SUCCESS) { | |
493 NotifyNetworkChanged(network_guid); | |
494 return; | |
495 } | |
496 } | |
497 } | |
498 CheckError(error_code, kWiFiServiceError, error); | |
499 } | |
500 | |
501 void WiFiServiceImpl::SetEventObservers( | |
502 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, | |
503 const NetworkGuidListCallback& networks_changed_observer, | |
504 const NetworkGuidListCallback& network_list_changed_observer) { | |
505 message_loop_proxy_.swap(message_loop_proxy); | |
506 networks_changed_observer_ = networks_changed_observer; | |
507 network_list_changed_observer_ = network_list_changed_observer; | |
508 } | |
509 | |
510 void WiFiServiceImpl::OnWlanNotificationCallback( | |
511 PWLAN_NOTIFICATION_DATA wlan_notification_data, | |
512 PVOID context) { | |
513 WiFiServiceImpl* service = reinterpret_cast<WiFiServiceImpl*>(context); | |
514 service->OnWlanNotification(wlan_notification_data); | |
515 } | |
516 | |
517 void WiFiServiceImpl::OnWlanNotification( | |
518 PWLAN_NOTIFICATION_DATA wlan_notification_data) { | |
519 if (message_loop_proxy_ == NULL) | |
520 return; | |
521 switch (wlan_notification_data->NotificationCode) { | |
522 case wlan_notification_acm_disconnected: | |
523 case wlan_notification_acm_connection_complete: | |
524 case wlan_notification_acm_connection_attempt_fail: { | |
525 PWLAN_CONNECTION_NOTIFICATION_DATA wlan_connection_data = | |
526 reinterpret_cast<PWLAN_CONNECTION_NOTIFICATION_DATA>( | |
527 wlan_notification_data->pData); | |
528 message_loop_proxy_->PostTask( | |
529 FROM_HERE, | |
530 base::Bind(&WiFiServiceImpl::NotifyNetworkChanged, | |
531 base::Unretained(this), | |
532 GUIDFromSSID(wlan_connection_data->dot11Ssid))); | |
533 break; | |
534 } | |
535 case wlan_notification_acm_scan_complete: | |
536 message_loop_proxy_->PostTask( | |
537 FROM_HERE, | |
538 base::Bind(&WiFiServiceImpl::OnNetworkScanCompleteOnMainThread, | |
539 base::Unretained(this))); | |
540 break; | |
541 } | |
542 } | |
543 | |
544 void WiFiServiceImpl::OnNetworkScanCompleteOnMainThread() { | |
545 NetworkList networks; | |
546 // Get current list of visible networks and notify that network list has | |
547 // changed. | |
548 DWORD error = GetVisibleNetworkList(&networks); | |
549 DCHECK(error == ERROR_SUCCESS); | |
550 if (error == ERROR_SUCCESS) | |
551 NotifyNetworkListChanged(networks); | |
552 } | |
553 | |
554 void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid, | |
555 int attempt) { | |
556 // If network didn't get connected in |kMaxAttempts|, then restore automatic | |
557 // network change notifications and stop waiting. | |
558 if (attempt > kMaxAttempts) { | |
559 DLOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to " | |
560 << network_guid; | |
561 enable_notify_network_changed_ = true; | |
562 RestoreNwCategoryWizard(); | |
563 return; | |
564 } | |
565 std::string connected_network_guid; | |
566 DWORD error = FindConnectedNetwork(&connected_network_guid); | |
567 if (network_guid == connected_network_guid) { | |
568 DLOG(INFO) << "WiFi Connected, Reset DHCP: " << network_guid; | |
569 // Even though wireless network is now connected, it may still be unusable, | |
570 // e.g. after Chromecast device reset. Reset DHCP on wireless network to | |
571 // work around this issue. | |
572 error = ResetDHCP(); | |
573 // Restore previously suppressed notifications. | |
574 enable_notify_network_changed_ = true; | |
575 RestoreNwCategoryWizard(); | |
576 NotifyNetworkChanged(network_guid); | |
577 } else { | |
578 // Continue waiting for network connection state change. | |
579 task_runner_->PostDelayedTask( | |
580 FROM_HERE, | |
581 base::Bind(&WiFiServiceImpl::WaitForNetworkConnect, | |
582 base::Unretained(this), | |
583 network_guid, | |
584 ++attempt), | |
585 base::TimeDelta::FromMilliseconds(kAttemptDelayMs)); | |
586 } | |
587 } | |
588 | |
589 bool WiFiServiceImpl::CheckError(DWORD error_code, | |
590 const std::string& error_name, | |
591 std::string* error) const { | |
592 if (error_code != ERROR_SUCCESS) { | |
593 DLOG(ERROR) << "WiFiService Error " << error_code << ": " << error_name; | |
594 *error = error_name; | |
595 return true; | |
596 } | |
597 return false; | |
598 } | |
599 | |
600 WiFiService::NetworkList::iterator WiFiServiceImpl::FindNetwork( | |
601 NetworkList& networks, | |
602 const std::string& network_guid) { | |
603 for (NetworkList::iterator it = networks.begin(); it != networks.end(); | |
604 ++it) { | |
605 if (it->guid == network_guid) | |
606 return it; | |
607 } | |
608 return networks.end(); | |
609 } | |
610 | |
611 DWORD WiFiServiceImpl::SaveCurrentConnectedNetwork( | |
612 std::string* connected_network_guid) { | |
613 // Find currently connected network. | |
614 DWORD error = FindConnectedNetwork(connected_network_guid); | |
615 if (error == ERROR_SUCCESS && !connected_network_guid->empty()) { | |
616 if (error == ERROR_SUCCESS) { | |
617 SaveTempProfile(*connected_network_guid); | |
618 std::string profile_xml; | |
619 error = GetProfile(*connected_network_guid, &profile_xml); | |
620 if (error == ERROR_SUCCESS) { | |
621 saved_profiles_xml_[*connected_network_guid] = profile_xml; | |
622 } | |
623 } | |
624 } | |
625 return error; | |
626 } | |
627 | |
628 void WiFiServiceImpl::SortNetworks(NetworkList* networks) { | |
629 networks->sort(NetworkProperties::OrderByType); | |
630 } | |
631 | |
632 DWORD WiFiServiceImpl::LoadWlanLibrary() { | |
633 // Use an absolute path to load the DLL to avoid DLL preloading attacks. | |
634 base::FilePath path; | |
635 if (!PathService::Get(base::DIR_SYSTEM, &path)) { | |
636 DLOG(ERROR) << "Unable to get system path."; | |
637 return ERROR_NOT_FOUND; | |
638 } | |
639 wlan_api_library_ = ::LoadLibraryEx(path.Append(kWlanApiDll).value().c_str(), | |
640 NULL, | |
641 LOAD_WITH_ALTERED_SEARCH_PATH); | |
642 if (!wlan_api_library_) { | |
643 DLOG(ERROR) << "Unable to load WlanApi.dll."; | |
644 return ERROR_NOT_FOUND; | |
645 } | |
646 | |
647 // Initialize WlanApi function pointers | |
648 WlanConnect_function_ = | |
649 reinterpret_cast<WlanConnectFunction>( | |
650 ::GetProcAddress(wlan_api_library_, kWlanConnect)); | |
651 WlanCloseHandle_function_ = | |
652 reinterpret_cast<WlanCloseHandleFunction>( | |
653 ::GetProcAddress(wlan_api_library_, kWlanCloseHandle)); | |
654 WlanDisconnect_function_ = | |
655 reinterpret_cast<WlanDisconnectFunction>( | |
656 ::GetProcAddress(wlan_api_library_, kWlanDisconnect)); | |
657 WlanEnumInterfaces_function_ = | |
658 reinterpret_cast<WlanEnumInterfacesFunction>( | |
659 ::GetProcAddress(wlan_api_library_, kWlanEnumInterfaces)); | |
660 WlanFreeMemory_function_ = | |
661 reinterpret_cast<WlanFreeMemoryFunction>( | |
662 ::GetProcAddress(wlan_api_library_, kWlanFreeMemory)); | |
663 WlanGetAvailableNetworkList_function_ = | |
664 reinterpret_cast<WlanGetAvailableNetworkListFunction>( | |
665 ::GetProcAddress(wlan_api_library_, kWlanGetAvailableNetworkList)); | |
666 WlanGetNetworkBssList_function_ = | |
667 reinterpret_cast<WlanGetNetworkBssListFunction>( | |
668 ::GetProcAddress(wlan_api_library_, kWlanGetNetworkBssList)); | |
669 WlanGetProfile_function_ = | |
670 reinterpret_cast<WlanGetProfileFunction>( | |
671 ::GetProcAddress(wlan_api_library_, kWlanGetProfile)); | |
672 WlanOpenHandle_function_ = | |
673 reinterpret_cast<WlanOpenHandleFunction>( | |
674 ::GetProcAddress(wlan_api_library_, kWlanOpenHandle)); | |
675 WlanRegisterNotification_function_ = | |
676 reinterpret_cast<WlanRegisterNotificationFunction>( | |
677 ::GetProcAddress(wlan_api_library_, kWlanRegisterNotification)); | |
678 WlanSaveTemporaryProfile_function_ = | |
679 reinterpret_cast<WlanSaveTemporaryProfileFunction>( | |
680 ::GetProcAddress(wlan_api_library_, kWlanSaveTemporaryProfile)); | |
681 WlanScan_function_ = | |
682 reinterpret_cast<WlanScanFunction>( | |
683 ::GetProcAddress(wlan_api_library_, kWlanScan)); | |
684 | |
685 if (!WlanConnect_function_ || | |
686 !WlanCloseHandle_function_ || | |
687 !WlanDisconnect_function_ || | |
688 !WlanEnumInterfaces_function_ || | |
689 !WlanFreeMemory_function_ || | |
690 !WlanGetAvailableNetworkList_function_ || | |
691 !WlanGetProfile_function_ || | |
692 !WlanOpenHandle_function_ || | |
693 !WlanRegisterNotification_function_ || | |
694 !WlanScan_function_) { | |
695 DLOG(ERROR) << "Unable to find required WlanApi function."; | |
696 FreeLibrary(wlan_api_library_); | |
697 wlan_api_library_ = NULL; | |
698 return ERROR_NOT_FOUND; | |
699 } | |
700 | |
701 // Some WlanApi functions may not be available on XP. | |
702 if (!WlanGetNetworkBssList_function_ || | |
703 !WlanSaveTemporaryProfile_function_) { | |
704 DLOG(INFO) << "WlanApi function is not be available on XP."; | |
705 } | |
706 | |
707 return ERROR_SUCCESS; | |
708 } | |
709 | |
710 DWORD WiFiServiceImpl::OpenClientHandle() { | |
711 DWORD error = LoadWlanLibrary(); | |
712 DWORD service_version = 0; | |
713 | |
714 if (error != ERROR_SUCCESS) | |
715 return error; | |
716 | |
717 // Open a handle to the service. | |
718 error = WlanOpenHandle_function_(1, NULL, &service_version, &client_); | |
719 | |
720 PWLAN_INTERFACE_INFO_LIST interface_list = NULL; | |
721 if (error == ERROR_SUCCESS) { | |
722 // Enumerate wireless interfaces. | |
723 error = WlanEnumInterfaces_function_(client_, NULL, &interface_list); | |
724 if (error == ERROR_SUCCESS) { | |
725 if (interface_list != NULL && interface_list->dwNumberOfItems != 0) { | |
726 // Remember first interface just in case if none are connected. | |
727 interface_guid_ = interface_list->InterfaceInfo[0].InterfaceGuid; | |
728 // Try to find a connected interface. | |
729 for (DWORD itf = 0; itf < interface_list->dwNumberOfItems; ++itf) { | |
730 if (interface_list->InterfaceInfo[itf].isState == | |
731 wlan_interface_state_connected) { | |
732 // Found connected interface, remember it! | |
733 interface_guid_ = interface_list->InterfaceInfo[itf].InterfaceGuid; | |
734 break; | |
735 } | |
736 } | |
737 WlanRegisterNotification_function_(client_, | |
738 WLAN_NOTIFICATION_SOURCE_ALL, | |
739 FALSE, | |
740 OnWlanNotificationCallback, | |
741 this, | |
742 NULL, | |
743 NULL); | |
744 } else { | |
745 error = ERROR_NOINTERFACE; | |
746 } | |
747 } | |
748 // Clean up. | |
749 if (interface_list != NULL) | |
750 WlanFreeMemory_function_(interface_list); | |
751 } | |
752 return error; | |
753 } | |
754 | |
755 DWORD WiFiServiceImpl::ResetDHCP() { | |
756 IP_ADAPTER_INDEX_MAP adapter_index_map = {0}; | |
757 DWORD error = FindAdapterIndexMapByGUID(interface_guid_, &adapter_index_map); | |
758 if (error == ERROR_SUCCESS) { | |
759 error = ::IpReleaseAddress(&adapter_index_map); | |
760 if (error == ERROR_SUCCESS) { | |
761 error = ::IpRenewAddress(&adapter_index_map); | |
762 } | |
763 } | |
764 return error; | |
765 } | |
766 | |
767 DWORD WiFiServiceImpl::FindAdapterIndexMapByGUID( | |
768 const GUID& interface_guid, | |
769 IP_ADAPTER_INDEX_MAP* adapter_index_map) { | |
770 string16 guid_string; | |
771 const int kGUIDSize = 39; | |
772 ::StringFromGUID2( | |
773 interface_guid, WriteInto(&guid_string, kGUIDSize), kGUIDSize); | |
774 | |
775 ULONG buffer_length = 0; | |
776 DWORD error = ::GetInterfaceInfo(NULL, &buffer_length); | |
777 if (error == ERROR_INSUFFICIENT_BUFFER) { | |
778 scoped_ptr<unsigned char[]> buffer(new unsigned char[buffer_length]); | |
779 IP_INTERFACE_INFO* interface_info = | |
780 reinterpret_cast<IP_INTERFACE_INFO*>(buffer.get()); | |
781 error = GetInterfaceInfo(interface_info, &buffer_length); | |
782 if (error == ERROR_SUCCESS) { | |
783 for (int adapter = 0; adapter < interface_info->NumAdapters; ++adapter) { | |
784 if (EndsWith( | |
785 interface_info->Adapter[adapter].Name, guid_string, false)) { | |
786 *adapter_index_map = interface_info->Adapter[adapter]; | |
787 break; | |
788 } | |
789 } | |
790 } | |
791 } | |
792 return error; | |
793 } | |
794 | |
795 DWORD WiFiServiceImpl::DisableNwCategoryWizard() { | |
796 base::win::RegKey nw_category_wizard; | |
797 DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER, | |
798 kNwCategoryWizardRegKey, | |
799 KEY_READ | KEY_SET_VALUE); | |
800 if (error == ERROR_SUCCESS) { | |
801 // Save current value if present. | |
802 if (nw_category_wizard.HasValue(kNwCategoryWizardRegValue)) { | |
803 DWORD saved = 0u; | |
804 error = nw_category_wizard.ReadValueDW(kNwCategoryWizardRegValue, | |
805 &saved); | |
806 if (error == ERROR_SUCCESS) { | |
807 error = nw_category_wizard.WriteValue(kNwCategoryWizardSavedRegValue, | |
808 saved); | |
809 } | |
810 } else { | |
811 // Mark that temporary value has to be deleted. | |
812 error = nw_category_wizard.WriteValue(kNwCategoryWizardDeleteRegValue, | |
813 1u); | |
814 } | |
815 | |
816 // Disable network location wizard. | |
817 error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue, | |
818 static_cast<DWORD>(0)); | |
819 } | |
820 | |
821 return error; | |
822 } | |
823 | |
824 DWORD WiFiServiceImpl::RestoreNwCategoryWizard() { | |
825 base::win::RegKey nw_category_wizard; | |
826 DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER, | |
827 kNwCategoryWizardRegKey, | |
828 KEY_SET_VALUE); | |
829 if (error == ERROR_SUCCESS) { | |
830 // Restore saved value if present. | |
831 if (nw_category_wizard.HasValue(kNwCategoryWizardSavedRegValue)) { | |
832 DWORD saved = 0u; | |
833 error = nw_category_wizard.ReadValueDW(kNwCategoryWizardSavedRegValue, | |
834 &saved); | |
835 if (error == ERROR_SUCCESS) { | |
836 error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue, | |
837 saved); | |
838 error = nw_category_wizard.DeleteValue(kNwCategoryWizardSavedRegValue); | |
839 } | |
840 } else if (nw_category_wizard.HasValue(kNwCategoryWizardDeleteRegValue)) { | |
841 error = nw_category_wizard.DeleteValue(kNwCategoryWizardRegValue); | |
842 error = nw_category_wizard.DeleteValue(kNwCategoryWizardDeleteRegValue); | |
843 } | |
844 } | |
845 | |
846 return error; | |
847 } | |
848 | |
849 DWORD WiFiServiceImpl::EnsureInitialized() { | |
850 if (client_ != NULL) | |
851 return ERROR_SUCCESS; | |
852 return ERROR_NOINTERFACE; | |
853 } | |
854 | |
855 DWORD WiFiServiceImpl::CloseClientHandle() { | |
856 DWORD error = ERROR_SUCCESS; | |
857 if (client_ != NULL) { | |
858 error = WlanCloseHandle_function_(client_, NULL); | |
859 client_ = NULL; | |
860 } | |
861 if (wlan_api_library_ != NULL) { | |
862 WlanConnect_function_ = NULL; | |
863 WlanCloseHandle_function_ = NULL; | |
864 WlanDisconnect_function_ = NULL; | |
865 WlanEnumInterfaces_function_ = NULL; | |
866 WlanFreeMemory_function_ = NULL; | |
867 WlanGetAvailableNetworkList_function_ = NULL; | |
868 WlanGetNetworkBssList_function_ = NULL; | |
869 WlanGetProfile_function_ = NULL; | |
870 WlanOpenHandle_function_ = NULL; | |
871 WlanRegisterNotification_function_ = NULL; | |
872 WlanSaveTemporaryProfile_function_ = NULL; | |
873 WlanScan_function_ = NULL; | |
874 ::FreeLibrary(wlan_api_library_); | |
875 wlan_api_library_ = NULL; | |
876 } | |
877 return error; | |
878 } | |
879 | |
880 DOT11_SSID WiFiServiceImpl::SSIDFromGUID( | |
881 const std::string& network_guid) const { | |
882 DOT11_SSID ssid = {0}; | |
883 if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) { | |
884 ssid.uSSIDLength = network_guid.length(); | |
885 strncpy(reinterpret_cast<char*>(ssid.ucSSID), | |
886 network_guid.c_str(), | |
887 ssid.uSSIDLength); | |
888 } else { | |
889 NOTREACHED(); | |
890 } | |
891 return ssid; | |
892 } | |
893 | |
894 std::string WiFiServiceImpl::SecurityFromDot11AuthAlg( | |
895 DOT11_AUTH_ALGORITHM alg) const { | |
896 switch (alg) { | |
897 case DOT11_AUTH_ALGO_RSNA: | |
898 return onc::wifi::kWPA_EAP; | |
899 case DOT11_AUTH_ALGO_RSNA_PSK: | |
900 return onc::wifi::kWPA_PSK; | |
901 case DOT11_AUTH_ALGO_80211_SHARED_KEY: | |
902 return onc::wifi::kWEP_PSK; | |
903 case DOT11_AUTH_ALGO_80211_OPEN: | |
904 return onc::wifi::kNone; | |
905 default: | |
906 return onc::wifi::kWPA_EAP; | |
907 } | |
908 } | |
909 | |
910 void WiFiServiceImpl::NetworkPropertiesFromAvailableNetwork( | |
911 const WLAN_AVAILABLE_NETWORK& wlan, | |
912 const WLAN_BSS_LIST& wlan_bss_list, | |
913 NetworkProperties* properties) { | |
914 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { | |
915 properties->connection_state = onc::connection_state::kConnected; | |
916 } else { | |
917 properties->connection_state = onc::connection_state::kNotConnected; | |
918 } | |
919 | |
920 properties->ssid = SSIDFromWLAN(wlan); | |
921 properties->name = properties->ssid; | |
922 properties->guid = GUIDFromWLAN(wlan); | |
923 properties->type = onc::network_type::kWiFi; | |
924 | |
925 for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) { | |
926 const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]); | |
927 if (bss_entry.dot11Ssid.uSSIDLength == wlan.dot11Ssid.uSSIDLength && | |
928 0 == memcmp(bss_entry.dot11Ssid.ucSSID, | |
929 wlan.dot11Ssid.ucSSID, | |
930 bss_entry.dot11Ssid.uSSIDLength)) { | |
931 if (bss_entry.ulChCenterFrequency < 3000000) | |
932 properties->frequency = kFrequency2400; | |
933 else | |
934 properties->frequency = kFrequency5000; | |
935 properties->frequency_list.push_back(properties->frequency); | |
936 properties->bssid = NetworkProperties::MacAddressAsString( | |
937 bss_entry.dot11Bssid); | |
938 } | |
939 } | |
940 properties->frequency_list.sort(); | |
941 properties->frequency_list.unique(); | |
942 properties->security = | |
943 SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm); | |
944 properties->signal_strength = wlan.wlanSignalQuality; | |
945 } | |
946 | |
947 // Get the list of visible wireless networks | |
948 DWORD WiFiServiceImpl::GetVisibleNetworkList(NetworkList* network_list) { | |
949 if (client_ == NULL) { | |
950 NOTREACHED(); | |
951 return ERROR_NOINTERFACE; | |
952 } | |
953 | |
954 DWORD error = ERROR_SUCCESS; | |
955 PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; | |
956 PWLAN_BSS_LIST bss_list = NULL; | |
957 | |
958 error = WlanGetAvailableNetworkList_function_( | |
959 client_, | |
960 &interface_guid_, | |
961 WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES, | |
962 NULL, | |
963 &available_network_list); | |
964 | |
965 std::set<std::string> network_guids; | |
966 | |
967 if (error == ERROR_SUCCESS && | |
968 available_network_list && | |
969 WlanGetNetworkBssList_function_) { | |
970 // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is | |
971 // needed, then different method of getting BSS (e.g. OID query) will have | |
972 // to be used. | |
973 error = WlanGetNetworkBssList_function_(client_, | |
974 &interface_guid_, | |
975 NULL, | |
976 dot11_BSS_type_any, | |
977 FALSE, | |
978 NULL, | |
979 &bss_list); | |
980 if (error == ERROR_SUCCESS && NULL != bss_list) { | |
981 for (DWORD i = 0; i < available_network_list->dwNumberOfItems; ++i) { | |
982 NetworkProperties network_properties; | |
983 NetworkPropertiesFromAvailableNetwork( | |
984 available_network_list->Network[i], | |
985 *bss_list, | |
986 &network_properties); | |
987 // Check for duplicate network guids. | |
988 if (network_guids.count(network_properties.guid)) { | |
989 // There should be no difference between properties except for | |
990 // |connection_state|, so mark it as |kConnected| if either one is. | |
991 if (network_properties.connection_state == | |
992 onc::connection_state::kConnected) { | |
993 NetworkList::iterator previous_network_properties = | |
994 FindNetwork(*network_list, network_properties.guid); | |
995 DCHECK(previous_network_properties != network_list->end()); | |
996 previous_network_properties->connection_state = | |
997 network_properties.connection_state; | |
998 } | |
999 } else { | |
1000 network_list->push_back(network_properties); | |
1001 } | |
1002 network_guids.insert(network_properties.guid); | |
1003 } | |
1004 } | |
1005 } | |
1006 | |
1007 // clean up | |
1008 if (available_network_list != NULL) { | |
1009 WlanFreeMemory_function_(available_network_list); | |
1010 } | |
1011 if (bss_list != NULL) { | |
1012 WlanFreeMemory_function_(bss_list); | |
1013 } | |
1014 return error; | |
1015 } | |
1016 | |
1017 // Find currently connected network. | |
1018 DWORD WiFiServiceImpl::FindConnectedNetwork( | |
1019 std::string* connected_network_guid) { | |
1020 if (client_ == NULL) { | |
1021 NOTREACHED(); | |
1022 return ERROR_NOINTERFACE; | |
1023 } | |
1024 | |
1025 DWORD error = ERROR_SUCCESS; | |
1026 PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; | |
1027 error = WlanGetAvailableNetworkList_function_( | |
1028 client_, &interface_guid_, 0, NULL, &available_network_list); | |
1029 | |
1030 if (error == ERROR_SUCCESS && NULL != available_network_list) { | |
1031 for (DWORD i = 0; i < available_network_list->dwNumberOfItems; ++i) { | |
1032 const WLAN_AVAILABLE_NETWORK& wlan = available_network_list->Network[i]; | |
1033 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { | |
1034 *connected_network_guid = GUIDFromWLAN(wlan); | |
1035 break; | |
1036 } | |
1037 } | |
1038 } | |
1039 | |
1040 // clean up | |
1041 if (available_network_list != NULL) { | |
1042 WlanFreeMemory_function_(available_network_list); | |
1043 } | |
1044 | |
1045 return error; | |
1046 } | |
1047 | |
1048 DWORD WiFiServiceImpl::GetDesiredBssList( | |
1049 DOT11_SSID& ssid, | |
1050 Frequency frequency, | |
1051 scoped_ptr<DOT11_BSSID_LIST>* desired_list) { | |
1052 if (client_ == NULL) { | |
1053 NOTREACHED(); | |
1054 return ERROR_NOINTERFACE; | |
1055 } | |
1056 | |
1057 desired_list->reset(); | |
1058 | |
1059 if (frequency == kFrequencyAny) | |
1060 return ERROR_SUCCESS; | |
1061 | |
1062 // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is | |
1063 // needed, then different method of getting BSS (e.g. OID query) will have | |
1064 // to be used. | |
1065 if (!WlanGetNetworkBssList_function_) | |
1066 return ERROR_NOT_SUPPORTED; | |
1067 | |
1068 DWORD error = ERROR_SUCCESS; | |
1069 PWLAN_BSS_LIST bss_list = NULL; | |
1070 | |
1071 error = WlanGetNetworkBssList_function_(client_, | |
1072 &interface_guid_, | |
1073 NULL, | |
1074 dot11_BSS_type_any, | |
1075 FALSE, | |
1076 NULL, | |
1077 &bss_list); | |
1078 if (error == ERROR_SUCCESS && NULL != bss_list) { | |
1079 unsigned int best_quality = 0u; | |
1080 size_t best_index = 0; | |
1081 Frequency bss_frequency; | |
1082 | |
1083 // Go through bss_list and find best quality BSSID with matching frequency. | |
1084 for (size_t bss = 0; bss < bss_list->dwNumberOfItems; ++bss) { | |
1085 const WLAN_BSS_ENTRY& bss_entry(bss_list->wlanBssEntries[bss]); | |
1086 if (bss_entry.dot11Ssid.uSSIDLength != ssid.uSSIDLength || | |
1087 0 != memcmp(bss_entry.dot11Ssid.ucSSID, | |
1088 ssid.ucSSID, | |
1089 bss_entry.dot11Ssid.uSSIDLength)) | |
1090 continue; | |
1091 | |
1092 if (bss_entry.ulChCenterFrequency < 3000000) | |
1093 bss_frequency = kFrequency2400; | |
1094 else | |
1095 bss_frequency = kFrequency5000; | |
1096 | |
1097 if (bss_frequency == frequency && | |
1098 bss_entry.uLinkQuality > best_quality) { | |
1099 best_quality = bss_entry.uLinkQuality; | |
1100 best_index = bss; | |
1101 } | |
1102 } | |
1103 | |
1104 // If any matching BSS were found, prepare the header. | |
1105 if (best_quality > 0) { | |
1106 const WLAN_BSS_ENTRY& bss_entry(bss_list->wlanBssEntries[best_index]); | |
1107 scoped_ptr<DOT11_BSSID_LIST> selected_list(new DOT11_BSSID_LIST); | |
1108 | |
1109 selected_list->Header.Revision = DOT11_BSSID_LIST_REVISION_1; | |
1110 selected_list->Header.Size = sizeof(DOT11_BSSID_LIST); | |
1111 selected_list->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; | |
1112 selected_list->uNumOfEntries = 1; | |
1113 selected_list->uTotalNumOfEntries = 1; | |
1114 std::copy(bss_entry.dot11Bssid, | |
1115 bss_entry.dot11Bssid+sizeof(bss_entry.dot11Bssid), | |
1116 selected_list->BSSIDs[0]); | |
1117 desired_list->swap(selected_list); | |
1118 DLOG(INFO) << "Quality: " << best_quality << " BSS: " | |
1119 << NetworkProperties::MacAddressAsString(bss_entry.dot11Bssid); | |
1120 } else { | |
1121 error = ERROR_NOT_FOUND; | |
1122 } | |
1123 } | |
1124 | |
1125 // clean up | |
1126 if (bss_list != NULL) { | |
1127 WlanFreeMemory_function_(bss_list); | |
1128 } | |
1129 return error; | |
1130 } | |
1131 | |
1132 | |
1133 DWORD WiFiServiceImpl::Connect(const std::string& network_guid, | |
1134 Frequency frequency) { | |
1135 if (client_ == NULL) { | |
1136 NOTREACHED(); | |
1137 return ERROR_NOINTERFACE; | |
1138 } | |
1139 | |
1140 DWORD error = ERROR_SUCCESS; | |
1141 DOT11_SSID ssid = SSIDFromGUID(network_guid); | |
1142 scoped_ptr<DOT11_BSSID_LIST> desired_bss_list; | |
1143 error = GetDesiredBssList(ssid, frequency, &desired_bss_list); | |
1144 if (error == ERROR_SUCCESS) { | |
1145 if (HaveProfile(network_guid)) { | |
1146 base::string16 profile_name = ProfileNameFromGUID(network_guid); | |
1147 WLAN_CONNECTION_PARAMETERS wlan_params = { | |
1148 wlan_connection_mode_profile, | |
1149 profile_name.c_str(), | |
1150 NULL, | |
1151 desired_bss_list.get(), | |
1152 dot11_BSS_type_any, | |
1153 0}; | |
1154 error = WlanConnect_function_( | |
1155 client_, &interface_guid_, &wlan_params, NULL); | |
1156 } else { | |
1157 // TODO(mef): wlan_connection_mode_discovery_unsecure is not available on | |
1158 // XP. If XP support is needed, then temporary profile will have to be | |
1159 // created. | |
1160 WLAN_CONNECTION_PARAMETERS wlan_params = { | |
1161 wlan_connection_mode_discovery_unsecure, | |
1162 NULL, | |
1163 &ssid, | |
1164 desired_bss_list.get(), | |
1165 dot11_BSS_type_infrastructure, | |
1166 0}; | |
1167 error = WlanConnect_function_( | |
1168 client_, &interface_guid_, &wlan_params, NULL); | |
1169 } | |
1170 } | |
1171 | |
1172 return error; | |
1173 } | |
1174 | |
1175 DWORD WiFiServiceImpl::Disconnect() { | |
1176 if (client_ == NULL) { | |
1177 NOTREACHED(); | |
1178 return ERROR_NOINTERFACE; | |
1179 } | |
1180 | |
1181 DWORD error = ERROR_SUCCESS; | |
1182 error = WlanDisconnect_function_(client_, &interface_guid_, NULL); | |
1183 return error; | |
1184 } | |
1185 | |
1186 DWORD WiFiServiceImpl::SaveTempProfile(const std::string& network_guid) { | |
1187 if (client_ == NULL) { | |
1188 NOTREACHED(); | |
1189 return ERROR_NOINTERFACE; | |
1190 } | |
1191 | |
1192 DWORD error = ERROR_SUCCESS; | |
1193 base::string16 profile_name = ProfileNameFromGUID(network_guid); | |
1194 // TODO(mef): WlanSaveTemporaryProfile is not available on XP. If XP support | |
1195 // is needed, then different method of saving network profile will have to be | |
1196 // used. | |
1197 if (WlanSaveTemporaryProfile_function_) { | |
1198 error = WlanSaveTemporaryProfile_function_(client_, | |
1199 &interface_guid_, | |
1200 profile_name.c_str(), | |
1201 NULL, | |
1202 WLAN_PROFILE_USER, | |
1203 true, | |
1204 NULL); | |
1205 } else { | |
1206 error = ERROR_NOT_SUPPORTED; | |
1207 } | |
1208 return error; | |
1209 } | |
1210 | |
1211 DWORD WiFiServiceImpl::GetProfile(const std::string& network_guid, | |
1212 std::string* profile_xml) { | |
1213 if (client_ == NULL) { | |
1214 NOTREACHED(); | |
1215 return ERROR_NOINTERFACE; | |
1216 } | |
1217 | |
1218 DWORD error = ERROR_SUCCESS; | |
1219 base::string16 profile_name = ProfileNameFromGUID(network_guid); | |
1220 LPWSTR str_profile_xml = NULL; | |
1221 error = WlanGetProfile_function_(client_, | |
1222 &interface_guid_, | |
1223 profile_name.c_str(), | |
1224 NULL, | |
1225 &str_profile_xml, | |
1226 NULL, | |
1227 NULL); | |
1228 | |
1229 if (error == ERROR_SUCCESS && str_profile_xml != NULL) { | |
1230 *profile_xml = base::UTF16ToUTF8(str_profile_xml); | |
1231 } | |
1232 // clean up | |
1233 if (str_profile_xml != NULL) { | |
1234 WlanFreeMemory_function_(str_profile_xml); | |
1235 } | |
1236 | |
1237 return error; | |
1238 } | |
1239 | |
1240 bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) { | |
1241 DWORD error = ERROR_SUCCESS; | |
1242 std::string profile_xml; | |
1243 return GetProfile(network_guid, &profile_xml) == ERROR_SUCCESS; | |
1244 } | |
1245 | |
1246 void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList& networks) { | |
1247 if (network_list_changed_observer_.is_null()) | |
1248 return; | |
1249 | |
1250 NetworkGuidList current_networks; | |
1251 for (NetworkList::const_iterator it = networks.begin(); | |
1252 it != networks.end(); | |
1253 ++it) { | |
1254 current_networks.push_back(it->guid); | |
1255 } | |
1256 | |
1257 message_loop_proxy_->PostTask( | |
1258 FROM_HERE, | |
1259 base::Bind(network_list_changed_observer_, current_networks)); | |
1260 } | |
1261 | |
1262 void WiFiServiceImpl::NotifyNetworkChanged(const std::string& network_guid) { | |
1263 if (enable_notify_network_changed_ && !networks_changed_observer_.is_null()) { | |
1264 DLOG(INFO) << "NotifyNetworkChanged: " << network_guid; | |
1265 NetworkGuidList changed_networks(1, network_guid); | |
1266 message_loop_proxy_->PostTask( | |
1267 FROM_HERE, | |
1268 base::Bind(networks_changed_observer_, changed_networks)); | |
1269 } | |
1270 } | |
1271 | |
1272 WiFiService* WiFiService::Create() { return new WiFiServiceImpl(); } | |
1273 | |
1274 } // namespace wifi | |
OLD | NEW |