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 "chrome/utility/wifi/wifi_service.h" | |
6 | |
7 #include <iphlpapi.h> | |
8 #include <objbase.h> | |
9 #include <wlanapi.h> | |
10 | |
11 #include "base/base_paths_win.h" | |
12 #include "base/bind.h" | |
13 #include "base/files/file_path.h" | |
14 #include "base/memory/ref_counted.h" | |
15 #include "base/message_loop/message_loop.h" | |
16 #include "base/path_service.h" | |
17 #include "base/strings/string16.h" | |
18 #include "base/strings/string_util.h" | |
19 #include "base/strings/utf_string_conversions.h" | |
20 #include "base/win/registry.h" | |
21 #include "components/onc/onc_constants.h" | |
22 | |
23 namespace { | |
24 const char kWiFiServiceError[] = "Error.WiFiService"; | |
25 const wchar_t kNwCategoryWizardRegKey[] = | |
26 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Network\\" | |
27 L"NwCategoryWizard"; | |
28 const wchar_t kNwCategoryWizardRegValue[] = L"Show"; | |
29 const wchar_t kWlanApiDll[] = L"wlanapi.dll"; | |
30 const char kWlanGetNetworkBssList[] = "WlanGetNetworkBssList"; | |
31 } // namespace | |
32 | |
33 namespace wifi { | |
34 | |
35 // Implementation of WiFiService for Windows. | |
36 class WiFiServiceImpl : public WiFiService, base::NonThreadSafe { | |
37 public: | |
38 WiFiServiceImpl(); | |
39 virtual ~WiFiServiceImpl(); | |
40 | |
41 // WiFiService interface implementation. | |
42 | |
43 virtual void GetProperties(const std::string& network_guid, | |
44 const NetworkPropertiesCallback& callback, | |
45 const ErrorCallback& error_callback) OVERRIDE; | |
46 | |
47 virtual void GetState(const std::string& network_guid, | |
48 const NetworkPropertiesCallback& callback, | |
49 const ErrorCallback& error_callback) OVERRIDE; | |
50 | |
51 virtual void GetManagedProperties( | |
52 const std::string& network_guid, | |
53 const DictionaryResultCallback& callback, | |
54 const ErrorCallback& error_callback) OVERRIDE; | |
55 | |
56 virtual void SetProperties(const std::string& network_guid, | |
57 const base::DictionaryValue& properties, | |
58 const StringResultCallback& callback, | |
59 const ErrorCallback& error_callback) OVERRIDE; | |
60 | |
61 virtual void GetVisibleNetworks(const NetworkListCallback& callback, | |
62 const ErrorCallback& error_callback) OVERRIDE; | |
63 | |
64 virtual void RequestNetworkScan() OVERRIDE; | |
65 | |
66 virtual void StartConnect(const std::string& network_guid, | |
67 const StringResultCallback& callback, | |
68 const ErrorCallback& error_callback) OVERRIDE; | |
69 | |
70 virtual void StartDisconnect(const std::string& network_guid, | |
71 const StringResultCallback& callback, | |
72 const ErrorCallback& error_callback) OVERRIDE; | |
73 | |
74 virtual void SetNetworksChangedObserver( | |
75 const NetworkGuidListCallback& observer) OVERRIDE; | |
76 | |
77 virtual void SetNetworkListChangedObserver( | |
78 const NetworkGuidListCallback& observer) OVERRIDE; | |
79 | |
80 private: | |
81 // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification | |
82 // on WiFiServiceImpl passed back as |context|. | |
83 static void __stdcall OnWlanNotificationCallback( | |
84 PWLAN_NOTIFICATION_DATA wlan_notification_data, | |
85 PVOID context); | |
86 | |
87 // Callback for Windows WLAN_NOTIFICATION. Called on random thread from | |
88 // OnWlanNotificationCallback. Handles network connectivity and scan complete | |
89 // notification and posts tasks to main thread. | |
90 void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data); | |
91 | |
92 // Handles NetworkScanComplete notification on main thread. Sends | |
93 // |NetworkListChanged| event with new list of visible networks. | |
94 void OnNetworkScanCompleteOnMainThread(); | |
95 | |
96 // Wait up to |kMaxAttempts| with |kAttemptDelayMs| delay for connection | |
97 // to network with |network_guid|. Reset DHCP and Notify that |NetworkChanged| | |
98 // upon success. | |
99 void WaitForNetworkConnect(const std::string& network_guid, int attempt); | |
100 | |
101 // Check |error_code| and if is not |ERROR_SUCCESS|, then run |error_callback| | |
102 // with |error_name|. | |
103 bool CheckError(const ErrorCallback& error_callback, | |
104 const std::string& error_name, | |
105 DWORD error_code) const; | |
106 | |
107 // Return |iterator| to network identified by |network_guid| in |networks| | |
108 // list. | |
109 NetworkList::iterator FindNetwork(NetworkList& networks, | |
110 const std::string& network_guid); | |
111 | |
112 // Save currently connected network profile and return its | |
113 // |connected_network_guid|, so it can be re-connected later. | |
114 DWORD SaveCurrentConnectedNetwork(std::string* connected_network_guid); | |
115 | |
116 // Sort networks, so connected/connecting is up front, then by type: | |
117 // Ethernet, WiFi, Cellular, VPN | |
118 static void SortNetworks(NetworkList* networks); | |
119 | |
120 // Open a WLAN client handle, register for WLAN notifications. | |
121 DWORD OpenClientHandle(); | |
122 | |
123 // Reset DHCP on wireless network to work around an issue when Windows | |
124 // takes forever to connect to the network, e.g. after Chromecast | |
125 // device reset. | |
126 DWORD ResetDHCP(); | |
127 | |
128 // Find |adapter_index_map| by |interface_guid| for DHCP reset. | |
129 DWORD FindAdapterIndexMapByGUID(const GUID& interface_guid, | |
130 IP_ADAPTER_INDEX_MAP* adapter_index_map); | |
131 | |
132 // Avoid the network location wizard to pop up when network is connected. | |
133 // Preserve current value in |saved_nw_category_wizard_|. | |
134 DWORD DisableNwCategoryWizard(); | |
135 | |
136 // Restore network location wizard to value saved by DisableNwCategoryWizard. | |
137 DWORD RestoreNwCategoryWizard(); | |
138 | |
139 // Ensure that |client_| handle is initialized. | |
140 DWORD EnsureInitialized(); | |
141 | |
142 // Close |client_| handle if it is open. | |
143 DWORD CloseClientHandle(); | |
144 | |
145 // Get |profile_name| from unique |network_guid|. | |
146 base::string16 ProfileNameFromGUID(const std::string& network_guid) const { | |
147 return base::UTF8ToUTF16(network_guid); | |
148 } | |
149 | |
150 // Get |dot11_ssid| from unique |network_guid|. | |
151 DOT11_SSID SSIDFromGUID(const std::string& network_guid) const; | |
152 | |
153 // Get unique |network_guid| string based on |dot11_ssid|. | |
154 std::string GUIDFromSSID(const DOT11_SSID& dot11_ssid) const { | |
155 return std::string(reinterpret_cast<const char*>(dot11_ssid.ucSSID), | |
156 dot11_ssid.uSSIDLength); | |
157 } | |
158 | |
159 // Get network |ssid| string based on |wlan|. | |
160 std::string SSIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const { | |
161 return GUIDFromSSID(wlan.dot11Ssid); | |
162 } | |
163 | |
164 // Get unique |network_guid| string based on |wlan|. | |
165 std::string GUIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const { | |
166 return SSIDFromWLAN(wlan); | |
167 } | |
168 | |
169 // Deduce |onc::wifi| security from |alg|. | |
170 std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const; | |
171 | |
172 // Populate |properties| based on |wlan| and its corresponding bss info from | |
173 // |wlan_bss_list|. | |
174 void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan, | |
175 const WLAN_BSS_LIST& wlan_bss_list, | |
176 NetworkProperties* properties); | |
177 | |
178 // Get the list of visible wireless networks. | |
179 DWORD GetVisibleNetworkList(NetworkList* network_list); | |
180 | |
181 // Find currently connected network if any. Populate |connected_network_guid| | |
182 // on success. | |
183 DWORD FindConnectedNetwork(std::string* connected_network_guid); | |
184 | |
185 // Connect to network |network_guid| using previosly stored profile if exists, | |
186 // or just network sid. | |
187 DWORD Connect(const std::string& network_guid); | |
188 | |
189 // Disconnect from currently connected network if any. | |
190 DWORD Disconnect(); | |
191 | |
192 // Save temporary wireless profile for |network_guid|. | |
193 DWORD SaveTempProfile(const std::string& network_guid); | |
194 | |
195 // Get previously stored |profile_xml| for |network_guid|. | |
196 DWORD GetProfile(const std::string& network_guid, std::string* profile_xml); | |
197 | |
198 // Return true if there is previously stored profile xml for |network_guid|. | |
199 bool HaveProfile(const std::string& network_guid); | |
200 | |
201 // Notify |network_list_changed_observer_| that list of visible networks has | |
202 // changed to |networks|. | |
203 void NotifyNetworkListChanged(const NetworkList& networks); | |
204 | |
205 // Notify |networks_changed_observer_| that network |network_guid| status has | |
206 // changed. | |
207 void NotifyNetworkChanged(const std::string& network_guid); | |
208 | |
209 // Load WlanApi.dll from SystemDirectory and get Api function pointers. | |
210 DWORD LoadWlanLibrary(); | |
211 | |
212 // WlanGetNetworkBssList | |
213 typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)( | |
214 HANDLE hClientHandle, | |
215 const GUID* pInterfaceGuid, | |
216 const PDOT11_SSID pDot11Ssid, | |
217 DOT11_BSS_TYPE dot11BssType, | |
218 BOOL bSecurityEnabled, | |
219 PVOID pReserved, | |
220 PWLAN_BSS_LIST* ppWlanBssList | |
221 ); | |
222 | |
223 // Instance of WlanApi.dll. | |
224 HINSTANCE wlan_api_library_; | |
225 // WlanGetNetworkBssList function may not be avaiable on Windows XP. | |
226 WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_; | |
Jói
2013/10/25 11:09:42
You need to manually bind all of the functions tha
mef
2013/10/25 15:09:05
Done.
| |
227 // WLAN service handle. | |
228 HANDLE client_; | |
229 // GUID of the currently connected interface, if any, otherwise the GUID of | |
230 // one of the WLAN interfaces. | |
231 GUID interface_guid_; | |
232 // Preserved WLAN profile xml. | |
233 std::map<std::string, std::string> saved_profiles_xml_; | |
234 // Observer to get notified when network(s) have changed (e.g. connect). | |
235 NetworkGuidListCallback networks_changed_observer_; | |
236 // Observer to get notified when network list has changed (scan complete). | |
237 NetworkGuidListCallback network_list_changed_observer_; | |
238 // Saved value of network location wizard show value. | |
239 scoped_ptr<DWORD> saved_nw_category_wizard_; | |
240 // Task runner to post tasks on main thread. | |
241 scoped_refptr<base::TaskRunner> task_runner_; | |
242 // If |false|, then |networks_changed_observer_| is not notified. | |
243 bool enable_notify_network_changed_; | |
244 // Number of attempts to check that network has connected successfully. | |
245 static const int kMaxAttempts = 100; | |
246 // Delay between attempts to check that network has connected successfully. | |
247 static const int kAttemptDelayMs = 100; | |
248 | |
249 DISALLOW_COPY_AND_ASSIGN(WiFiServiceImpl); | |
250 }; | |
251 | |
252 WiFiServiceImpl::WiFiServiceImpl() | |
253 : wlan_api_library_(NULL), | |
254 WlanGetNetworkBssList_function_(NULL), | |
255 client_(NULL), | |
256 enable_notify_network_changed_(true) {} | |
257 | |
258 WiFiServiceImpl::~WiFiServiceImpl() { CloseClientHandle(); } | |
259 | |
260 void WiFiServiceImpl::GetProperties(const std::string& network_guid, | |
261 const NetworkPropertiesCallback& callback, | |
262 const ErrorCallback& error_callback) { | |
263 DWORD error = EnsureInitialized(); | |
cpu_(ooo_6.6-7.5)
2013/10/25 16:51:09
shouldn't be an Initialize method that the client
mef
2013/10/25 18:00:38
Sounds good, will do.
mef
2013/10/25 19:43:17
Done.
| |
264 if (error == ERROR_SUCCESS) { | |
265 NetworkList network_list; | |
266 error = GetVisibleNetworkList(&network_list); | |
267 if (error == ERROR_SUCCESS && !network_list.empty()) { | |
268 NetworkList::const_iterator it = FindNetwork(network_list, network_guid); | |
269 if (it != network_list.end()) { | |
270 DLOG(INFO) << "Get Properties: " << network_guid << ":" | |
271 << it->connection_state; | |
272 callback.Run(network_guid, *it); | |
273 return; | |
274 } else { | |
275 error = ERROR_NOT_FOUND; | |
276 } | |
277 } | |
278 } | |
279 | |
280 CheckError(error_callback, kWiFiServiceError, error); | |
281 } | |
282 | |
283 void WiFiServiceImpl::GetState(const std::string& network_guid, | |
284 const NetworkPropertiesCallback& callback, | |
285 const ErrorCallback& error_callback) { | |
286 // This method is not implemented in first version as it is not used by | |
287 // Google Cast extension. | |
288 CheckError(error_callback, kWiFiServiceError, ERROR_CALL_NOT_IMPLEMENTED); | |
289 } | |
290 | |
291 void WiFiServiceImpl::GetManagedProperties( | |
292 const std::string& network_guid, | |
293 const DictionaryResultCallback& callback, | |
294 const ErrorCallback& error_callback) { | |
295 // This method is not implemented in first version as it is not used by | |
296 // Google Cast extension. | |
297 CheckError(error_callback, kWiFiServiceError, ERROR_CALL_NOT_IMPLEMENTED); | |
298 } | |
299 | |
300 void WiFiServiceImpl::SetProperties(const std::string& network_guid, | |
301 const base::DictionaryValue& properties, | |
302 const StringResultCallback& callback, | |
303 const ErrorCallback& error_callback) { | |
304 // This method is not implemented in first version as it is not used by | |
305 // Google Cast extension. | |
306 CheckError(error_callback, kWiFiServiceError, ERROR_CALL_NOT_IMPLEMENTED); | |
307 } | |
308 | |
309 void WiFiServiceImpl::GetVisibleNetworks(const NetworkListCallback& callback, | |
310 const ErrorCallback& error_callback) { | |
311 DWORD error = EnsureInitialized(); | |
312 | |
313 if (error == ERROR_SUCCESS) { | |
314 NetworkList network_list; | |
315 error = GetVisibleNetworkList(&network_list); | |
316 if (error == ERROR_SUCCESS && !network_list.empty()) { | |
317 SortNetworks(&network_list); | |
318 callback.Run(network_list); | |
319 return; | |
320 } | |
321 } | |
322 | |
323 CheckError(error_callback, kWiFiServiceError, error); | |
324 } | |
325 | |
326 void WiFiServiceImpl::RequestNetworkScan() { | |
327 DWORD error = EnsureInitialized(); | |
328 if (error == ERROR_SUCCESS) { | |
329 WlanScan(client_, &interface_guid_, NULL, NULL, NULL); | |
330 } | |
331 } | |
332 | |
333 void WiFiServiceImpl::StartConnect(const std::string& network_guid, | |
334 const StringResultCallback& callback, | |
335 const ErrorCallback& error_callback) { | |
336 DLOG(INFO) << "Start Connect: " << network_guid; | |
337 DWORD error = EnsureInitialized(); | |
338 if (error == ERROR_SUCCESS) { | |
339 std::string connected_network_guid; | |
340 error = SaveCurrentConnectedNetwork(&connected_network_guid); | |
341 if (error == ERROR_SUCCESS) { | |
342 // Connect only if network |network_guid| is not connected already. | |
343 if (network_guid != connected_network_guid) | |
344 error = Connect(network_guid); | |
345 if (error == ERROR_SUCCESS) { | |
346 DisableNwCategoryWizard(); | |
347 callback.Run(network_guid); | |
348 // Notify that previously connected network has changed. | |
349 NotifyNetworkChanged(connected_network_guid); | |
350 // Start waiting for network connection state change. | |
351 if (!networks_changed_observer_.is_null()) { | |
352 // Disable automatic network change notifications as they get fired | |
353 // when network is just connected, but not yet accessible (doesn't | |
354 // have valid IP address). | |
355 enable_notify_network_changed_ = false; | |
356 WaitForNetworkConnect(network_guid, 0); | |
357 return; | |
358 } | |
359 } | |
360 } | |
361 } | |
362 CheckError(error_callback, kWiFiServiceError, error); | |
363 } | |
364 | |
365 void WiFiServiceImpl::StartDisconnect(const std::string& network_guid, | |
366 const StringResultCallback& callback, | |
367 const ErrorCallback& error_callback) { | |
368 DLOG(INFO) << "Start Disconnect: " << network_guid; | |
369 DWORD error = EnsureInitialized(); | |
370 if (error == ERROR_SUCCESS) { | |
371 std::string connected_network_guid; | |
372 error = SaveCurrentConnectedNetwork(&connected_network_guid); | |
373 if (error == ERROR_SUCCESS && network_guid == connected_network_guid) { | |
374 error = Disconnect(); | |
375 if (error == ERROR_SUCCESS) { | |
376 callback.Run(network_guid); | |
377 NotifyNetworkChanged(network_guid); | |
378 return; | |
379 } | |
380 } | |
381 } | |
382 CheckError(error_callback, kWiFiServiceError, error); | |
383 } | |
384 | |
385 void WiFiServiceImpl::SetNetworksChangedObserver( | |
386 const NetworkGuidListCallback& observer) { | |
387 networks_changed_observer_ = observer; | |
388 } | |
389 | |
390 void WiFiServiceImpl::SetNetworkListChangedObserver( | |
391 const NetworkGuidListCallback& observer) { | |
392 network_list_changed_observer_ = observer; | |
393 } | |
394 | |
395 void WiFiServiceImpl::OnWlanNotificationCallback( | |
396 PWLAN_NOTIFICATION_DATA wlan_notification_data, | |
397 PVOID context) { | |
398 WiFiServiceImpl* service = reinterpret_cast<WiFiServiceImpl*>(context); | |
399 service->OnWlanNotification(wlan_notification_data); | |
400 } | |
401 | |
402 void WiFiServiceImpl::OnWlanNotification( | |
403 PWLAN_NOTIFICATION_DATA wlan_notification_data) { | |
404 switch (wlan_notification_data->NotificationCode) { | |
405 case wlan_notification_acm_disconnected: | |
406 case wlan_notification_acm_connection_complete: | |
407 case wlan_notification_acm_connection_attempt_fail: { | |
408 PWLAN_CONNECTION_NOTIFICATION_DATA wlan_connection_data = | |
409 reinterpret_cast<PWLAN_CONNECTION_NOTIFICATION_DATA>( | |
410 wlan_notification_data->pData); | |
411 task_runner_->PostTask( | |
412 FROM_HERE, | |
413 base::Bind(&WiFiServiceImpl::NotifyNetworkChanged, | |
414 base::Unretained(this), | |
415 GUIDFromSSID(wlan_connection_data->dot11Ssid))); | |
416 break; | |
417 } | |
418 case wlan_notification_acm_scan_complete: | |
419 task_runner_->PostTask( | |
420 FROM_HERE, | |
421 base::Bind(&WiFiServiceImpl::OnNetworkScanCompleteOnMainThread, | |
422 base::Unretained(this))); | |
423 break; | |
424 } | |
425 } | |
426 | |
427 void WiFiServiceImpl::OnNetworkScanCompleteOnMainThread() { | |
428 NetworkList networks; | |
429 // Get current list of visible networks and notify that network list has | |
430 // changed. | |
431 DWORD error = GetVisibleNetworkList(&networks); | |
432 DCHECK(error == ERROR_SUCCESS); | |
433 if (error == ERROR_SUCCESS) | |
434 NotifyNetworkListChanged(networks); | |
435 } | |
436 | |
437 void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid, | |
438 int attempt) { | |
439 // If network didn't get connected in |kMaxAttempts|, then restore automatic | |
440 // network change notifications and stop waiting. | |
441 if (attempt > kMaxAttempts) { | |
442 DLOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to " | |
443 << network_guid; | |
444 enable_notify_network_changed_ = true; | |
445 RestoreNwCategoryWizard(); | |
446 return; | |
447 } | |
448 std::string connected_network_guid; | |
449 DWORD error = FindConnectedNetwork(&connected_network_guid); | |
450 if (network_guid == connected_network_guid) { | |
451 DLOG(INFO) << "WiFi Connected, Reset DHCP: " << network_guid; | |
452 // Even though wireless network is now connected, it may still be unusable, | |
453 // e.g. after Chromecast device reset. Reset DHCP on wireless network to | |
454 // work around this issue. | |
455 error = ResetDHCP(); | |
456 // Restore previously suppressed notifications. | |
457 enable_notify_network_changed_ = true; | |
458 RestoreNwCategoryWizard(); | |
459 NotifyNetworkChanged(network_guid); | |
460 } else { | |
461 // Continue waiting for network connection state change. | |
462 base::MessageLoop::current()->PostDelayedTask( | |
463 FROM_HERE, | |
464 base::Bind(&WiFiServiceImpl::WaitForNetworkConnect, | |
465 base::Unretained(this), | |
466 network_guid, | |
467 ++attempt), | |
468 base::TimeDelta::FromMilliseconds(kAttemptDelayMs)); | |
469 } | |
470 } | |
471 | |
472 bool WiFiServiceImpl::CheckError(const ErrorCallback& error_callback, | |
473 const std::string& error_name, | |
474 DWORD error_code) const { | |
475 if (error_code != ERROR_SUCCESS) { | |
476 DLOG(ERROR) << "WiFiService Error " << error_code << ": " << error_name; | |
477 scoped_ptr<base::DictionaryValue> error_data(new base::DictionaryValue); | |
478 error_data->SetInteger("Win32ErrorCode", error_code); | |
479 error_callback.Run(error_name, error_data.Pass()); | |
480 return true; | |
481 } | |
482 return false; | |
483 } | |
484 | |
485 WiFiService::NetworkList::iterator WiFiServiceImpl::FindNetwork( | |
486 NetworkList& networks, | |
487 const std::string& network_guid) { | |
488 for (NetworkList::iterator it = networks.begin(); it != networks.end(); | |
489 ++it) { | |
490 if (it->guid == network_guid) | |
491 return it; | |
492 } | |
493 return networks.end(); | |
494 } | |
495 | |
496 DWORD WiFiServiceImpl::SaveCurrentConnectedNetwork( | |
497 std::string* connected_network_guid) { | |
498 // Find currently connected network. | |
499 DWORD error = FindConnectedNetwork(connected_network_guid); | |
500 if (error == ERROR_SUCCESS && !connected_network_guid->empty()) { | |
501 if (error == ERROR_SUCCESS) { | |
502 SaveTempProfile(*connected_network_guid); | |
503 std::string profile_xml; | |
504 error = GetProfile(*connected_network_guid, &profile_xml); | |
505 if (error == ERROR_SUCCESS) { | |
506 saved_profiles_xml_[*connected_network_guid] = profile_xml; | |
507 } | |
508 } | |
509 } | |
510 return error; | |
511 } | |
512 | |
513 void WiFiServiceImpl::SortNetworks(NetworkList* networks) { | |
514 networks->sort(NetworkProperties::OrderByType); | |
515 } | |
516 | |
517 | |
518 DWORD WiFiServiceImpl::LoadWlanLibrary() { | |
519 // Use an absolute path to load the DLL to avoid DLL preloading attacks. | |
520 base::FilePath path; | |
521 if (!PathService::Get(base::DIR_SYSTEM, &path)) { | |
522 DLOG(ERROR) << "Unable to get system path."; | |
523 return ERROR_NOT_FOUND; | |
524 } | |
525 wlan_api_library_ = ::LoadLibraryEx(path.Append(kWlanApiDll).value().c_str(), | |
526 NULL, | |
527 LOAD_WITH_ALTERED_SEARCH_PATH); | |
528 if (!wlan_api_library_) { | |
529 DLOG(ERROR) << "Unable to load WlanApi.dll."; | |
530 return ERROR_NOT_FOUND; | |
531 } | |
532 WlanGetNetworkBssList_function_ = | |
533 reinterpret_cast<WlanGetNetworkBssListFunction>( | |
534 ::GetProcAddress(wlan_api_library_, "WlanGetNetworkBssList")); | |
535 if (!WlanGetNetworkBssList_function_) { | |
536 DLOG(ERROR) << "Unable to find WlanGetNetworkBssList function."; | |
Jói
2013/10/25 11:09:42
This is an expected case on XP and as such shouldn
mef
2013/10/25 15:09:05
Done.
| |
537 FreeLibrary(wlan_api_library_); | |
538 wlan_api_library_ = NULL; | |
539 return ERROR_NOT_FOUND; | |
540 } | |
541 | |
542 return ERROR_SUCCESS; | |
543 } | |
544 | |
545 DWORD WiFiServiceImpl::OpenClientHandle() { | |
546 CloseClientHandle(); | |
547 | |
548 DWORD error = LoadWlanLibrary(); | |
549 DWORD service_version = 0; | |
550 | |
551 if (error != ERROR_SUCCESS) | |
552 return error; | |
553 | |
554 // Open a handle to the service. | |
555 error = ::WlanOpenHandle(1, NULL, &service_version, &client_); | |
cpu_(ooo_6.6-7.5)
2013/10/25 16:51:09
this does not work on XP sp2, see https://support.
mef
2013/10/25 18:00:38
Done. I've changed all WlanApi functions to be exp
| |
556 | |
557 PWLAN_INTERFACE_INFO_LIST interface_list = NULL; | |
558 if (error == ERROR_SUCCESS) { | |
559 // Enumerate wireless interfaces. | |
560 error = ::WlanEnumInterfaces(client_, NULL, &interface_list); | |
561 if (error == ERROR_SUCCESS) { | |
562 if (interface_list != NULL && interface_list->dwNumberOfItems != 0) { | |
563 // Remember first interface just in case if none are connected. | |
564 interface_guid_ = interface_list->InterfaceInfo[0].InterfaceGuid; | |
565 // Try to find a connected interface. | |
566 for (DWORD itf = 0; itf < interface_list->dwNumberOfItems; ++itf) { | |
567 if (interface_list->InterfaceInfo[itf].isState == | |
568 wlan_interface_state_connected) { | |
569 // Found connected interface, remember it! | |
570 interface_guid_ = interface_list->InterfaceInfo[itf].InterfaceGuid; | |
571 break; | |
572 } | |
573 } | |
574 ::WlanRegisterNotification(client_, | |
575 WLAN_NOTIFICATION_SOURCE_ALL, | |
576 FALSE, | |
577 OnWlanNotificationCallback, | |
578 this, | |
579 NULL, | |
580 NULL); | |
581 } else { | |
582 error = ERROR_NOINTERFACE; | |
583 } | |
584 } | |
585 // Clean up. | |
586 if (interface_list != NULL) | |
587 ::WlanFreeMemory(interface_list); | |
588 } | |
589 return error; | |
590 } | |
591 | |
592 DWORD WiFiServiceImpl::ResetDHCP() { | |
593 IP_ADAPTER_INDEX_MAP adapter_index_map = {0}; | |
594 DWORD error = FindAdapterIndexMapByGUID(interface_guid_, &adapter_index_map); | |
595 if (error == ERROR_SUCCESS) { | |
596 error = ::IpReleaseAddress(&adapter_index_map); | |
597 if (error == ERROR_SUCCESS) { | |
598 error = ::IpRenewAddress(&adapter_index_map); | |
599 } | |
600 } | |
601 return error; | |
602 } | |
603 | |
604 DWORD WiFiServiceImpl::FindAdapterIndexMapByGUID( | |
605 const GUID& interface_guid, | |
606 IP_ADAPTER_INDEX_MAP* adapter_index_map) { | |
607 string16 guid_string; | |
608 const int kGUIDSize = 39; | |
609 ::StringFromGUID2( | |
610 interface_guid, WriteInto(&guid_string, kGUIDSize), kGUIDSize); | |
611 | |
612 ULONG buffer_length = 0; | |
613 DWORD error = ::GetInterfaceInfo(NULL, &buffer_length); | |
614 if (error == ERROR_INSUFFICIENT_BUFFER) { | |
615 scoped_ptr<unsigned char[]> buffer(new unsigned char[buffer_length]); | |
616 IP_INTERFACE_INFO* interface_info = | |
617 reinterpret_cast<IP_INTERFACE_INFO*>(buffer.get()); | |
618 error = GetInterfaceInfo(interface_info, &buffer_length); | |
619 if (error == ERROR_SUCCESS) { | |
620 for (int adapter = 0; adapter < interface_info->NumAdapters; ++adapter) { | |
621 if (EndsWith( | |
622 interface_info->Adapter[adapter].Name, guid_string, false)) { | |
623 *adapter_index_map = interface_info->Adapter[adapter]; | |
624 break; | |
625 } | |
626 } | |
627 } | |
628 } | |
629 return error; | |
630 } | |
631 | |
632 DWORD WiFiServiceImpl::DisableNwCategoryWizard() { | |
633 base::win::RegKey nw_category_wizard; | |
634 DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER, | |
635 kNwCategoryWizardRegKey, | |
636 KEY_READ | KEY_SET_VALUE); | |
637 if (error == ERROR_SUCCESS) { | |
638 // Save current value if present. | |
639 if (nw_category_wizard.HasValue(kNwCategoryWizardRegValue)) { | |
640 saved_nw_category_wizard_.reset(new(DWORD)); | |
641 error = nw_category_wizard.ReadValueDW(kNwCategoryWizardRegValue, | |
642 saved_nw_category_wizard_.get()); | |
643 } | |
644 // Disable network location wizard. | |
645 error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue, | |
646 static_cast<DWORD>(0)); | |
cpu_(ooo_6.6-7.5)
2013/10/25 16:51:09
what if you crash after setting this? no wizard fo
mef
2013/10/25 18:00:38
I guess so. I can preserve it using another value
mef
2013/10/25 19:43:17
Done.
| |
647 } | |
648 | |
649 return error; | |
650 } | |
651 | |
652 DWORD WiFiServiceImpl::RestoreNwCategoryWizard() { | |
653 base::win::RegKey nw_category_wizard; | |
654 DWORD error = nw_category_wizard.Open(HKEY_CURRENT_USER, | |
655 kNwCategoryWizardRegKey, | |
656 KEY_SET_VALUE); | |
657 if (error == ERROR_SUCCESS) { | |
658 // Restore saved value if any, or delete value from the key. | |
659 if (saved_nw_category_wizard_.get()) { | |
660 error = nw_category_wizard.WriteValue(kNwCategoryWizardRegValue, | |
661 *saved_nw_category_wizard_); | |
662 saved_nw_category_wizard_.reset(); | |
663 } else { | |
664 error = nw_category_wizard.DeleteValue(kNwCategoryWizardRegValue); | |
665 } | |
666 } | |
667 | |
668 return error; | |
669 } | |
670 | |
671 DWORD WiFiServiceImpl::EnsureInitialized() { | |
672 DCHECK(CalledOnValidThread()); | |
673 if (client_ != NULL) | |
674 return ERROR_SUCCESS; | |
675 if (task_runner_.get() == NULL) | |
676 task_runner_ = base::MessageLoopProxy::current(); | |
677 | |
678 return OpenClientHandle(); | |
679 } | |
680 | |
681 DWORD WiFiServiceImpl::CloseClientHandle() { | |
682 DWORD error = ERROR_SUCCESS; | |
683 if (client_ != NULL) { | |
684 error = ::WlanCloseHandle(client_, NULL); | |
685 client_ = NULL; | |
686 } | |
687 if (wlan_api_library_ != NULL) { | |
688 WlanGetNetworkBssList_function_ = NULL; | |
689 ::FreeLibrary(wlan_api_library_); | |
cpu_(ooo_6.6-7.5)
2013/10/25 16:51:09
If it was me, I would not attempt to unload this d
mef
2013/10/25 18:00:38
Sounds good, but could you elaborate on the motiva
| |
690 wlan_api_library_ = NULL; | |
691 } | |
692 return error; | |
693 } | |
694 | |
695 DOT11_SSID WiFiServiceImpl::SSIDFromGUID( | |
696 const std::string& network_guid) const { | |
697 DOT11_SSID ssid = {0}; | |
698 if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) { | |
699 ssid.uSSIDLength = network_guid.length(); | |
700 strncpy(reinterpret_cast<char*>(ssid.ucSSID), | |
701 network_guid.c_str(), | |
702 ssid.uSSIDLength); | |
703 } else { | |
704 NOTREACHED(); | |
705 } | |
706 return ssid; | |
707 } | |
708 | |
709 std::string WiFiServiceImpl::SecurityFromDot11AuthAlg( | |
710 DOT11_AUTH_ALGORITHM alg) const { | |
711 switch (alg) { | |
712 case DOT11_AUTH_ALGO_RSNA: | |
713 return onc::wifi::kWPA_EAP; | |
714 case DOT11_AUTH_ALGO_RSNA_PSK: | |
715 return onc::wifi::kWPA_PSK; | |
716 case DOT11_AUTH_ALGO_80211_SHARED_KEY: | |
717 return onc::wifi::kWEP_PSK; | |
718 case DOT11_AUTH_ALGO_80211_OPEN: | |
719 return onc::wifi::kNone; | |
720 default: | |
721 return onc::wifi::kWPA_EAP; | |
722 } | |
723 } | |
724 | |
725 void WiFiServiceImpl::NetworkPropertiesFromAvailableNetwork( | |
726 const WLAN_AVAILABLE_NETWORK& wlan, | |
727 const WLAN_BSS_LIST& wlan_bss_list, | |
728 NetworkProperties* properties) { | |
729 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { | |
730 properties->connection_state = onc::connection_state::kConnected; | |
731 } else { | |
732 properties->connection_state = onc::connection_state::kNotConnected; | |
733 } | |
734 | |
735 properties->ssid = SSIDFromWLAN(wlan); | |
736 properties->name = properties->ssid; | |
737 properties->guid = GUIDFromWLAN(wlan); | |
738 properties->type = onc::network_type::kWiFi; | |
739 | |
740 for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) { | |
741 const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]); | |
742 if (bss_entry.dot11Ssid.uSSIDLength == wlan.dot11Ssid.uSSIDLength && | |
743 0 == memcmp(bss_entry.dot11Ssid.ucSSID, | |
744 wlan.dot11Ssid.ucSSID, | |
745 bss_entry.dot11Ssid.uSSIDLength)) { | |
746 if (bss_entry.ulChCenterFrequency < 3000000) | |
747 properties->frequency = kFrequency2400; | |
748 else | |
749 properties->frequency = kFrequency5000; | |
750 properties->frequency_list.push_back(properties->frequency); | |
751 properties->bssid = NetworkProperties::MacAddressAsString( | |
752 bss_entry.dot11Bssid); | |
753 } | |
754 } | |
755 properties->frequency_list.sort(); | |
756 properties->frequency_list.unique(); | |
757 properties->security = | |
758 SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm); | |
759 properties->signal_strength = wlan.wlanSignalQuality; | |
760 } | |
761 | |
762 // Get the list of visible wireless networks | |
763 DWORD WiFiServiceImpl::GetVisibleNetworkList(NetworkList* network_list) { | |
764 if (client_ == NULL) { | |
765 NOTREACHED(); | |
766 return ERROR_NOINTERFACE; | |
767 } | |
768 | |
769 DWORD error = ERROR_SUCCESS; | |
770 PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; | |
771 PWLAN_BSS_LIST bss_list = NULL; | |
772 | |
773 error = ::WlanGetAvailableNetworkList( | |
774 client_, | |
775 &interface_guid_, | |
776 WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES, | |
777 NULL, | |
778 &available_network_list); | |
779 | |
780 std::set<std::string> network_guids; | |
781 | |
782 if (error == ERROR_SUCCESS && NULL != available_network_list) { | |
783 // TODO(mef): WlanGetNetworkBssList is not available on XP. If XP support is | |
784 // needed, then different method of getting BSS (e.g. OID query) will have | |
785 // to be used. | |
786 error = WlanGetNetworkBssList_function_(client_, | |
Jói
2013/10/25 11:09:42
You shouldn't call this function unless it is avai
mef
2013/10/25 15:09:05
Done.
| |
787 &interface_guid_, | |
788 NULL, | |
789 dot11_BSS_type_any, | |
790 FALSE, | |
791 NULL, | |
792 &bss_list); | |
793 if (error == ERROR_SUCCESS && NULL != bss_list) { | |
794 for (DWORD i = 0; i < available_network_list->dwNumberOfItems; ++i) { | |
795 NetworkProperties network_properties; | |
796 NetworkPropertiesFromAvailableNetwork( | |
797 available_network_list->Network[i], | |
798 *bss_list, | |
799 &network_properties); | |
800 // Check for duplicate network guids. | |
801 if (network_guids.count(network_properties.guid)) { | |
802 // There should be no difference between properties except for | |
803 // |connection_state|, so mark it as |kConnected| if either one is. | |
804 if (network_properties.connection_state == | |
805 onc::connection_state::kConnected) { | |
806 NetworkList::iterator previous_network_properties = | |
807 FindNetwork(*network_list, network_properties.guid); | |
808 DCHECK(previous_network_properties != network_list->end()); | |
809 previous_network_properties->connection_state = | |
810 network_properties.connection_state; | |
811 } | |
812 } else { | |
813 network_list->push_back(network_properties); | |
814 } | |
815 network_guids.insert(network_properties.guid); | |
816 } | |
817 } | |
818 } | |
819 | |
820 // clean up | |
821 if (available_network_list != NULL) { | |
822 ::WlanFreeMemory(available_network_list); | |
823 } | |
824 if (bss_list != NULL) { | |
825 ::WlanFreeMemory(bss_list); | |
826 } | |
827 return error; | |
828 } | |
829 | |
830 // Find currently connected network. | |
831 DWORD WiFiServiceImpl::FindConnectedNetwork( | |
832 std::string* connected_network_guid) { | |
833 if (client_ == NULL) { | |
834 NOTREACHED(); | |
835 return ERROR_NOINTERFACE; | |
836 } | |
837 | |
838 DWORD error = ERROR_SUCCESS; | |
839 PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; | |
840 error = ::WlanGetAvailableNetworkList( | |
841 client_, &interface_guid_, 0, NULL, &available_network_list); | |
842 | |
843 if (error == ERROR_SUCCESS && NULL != available_network_list) { | |
844 for (DWORD i = 0; i < available_network_list->dwNumberOfItems; ++i) { | |
845 const WLAN_AVAILABLE_NETWORK& wlan = available_network_list->Network[i]; | |
846 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { | |
847 *connected_network_guid = GUIDFromWLAN(wlan); | |
848 break; | |
849 } | |
850 } | |
851 } | |
852 | |
853 // clean up | |
854 if (available_network_list != NULL) { | |
855 ::WlanFreeMemory(available_network_list); | |
856 } | |
857 | |
858 return error; | |
859 } | |
860 | |
861 DWORD WiFiServiceImpl::Connect(const std::string& network_guid) { | |
862 if (client_ == NULL) { | |
863 NOTREACHED(); | |
864 return ERROR_NOINTERFACE; | |
865 } | |
866 | |
867 DWORD error = ERROR_SUCCESS; | |
868 base::string16 profile_name = ProfileNameFromGUID(network_guid); | |
869 | |
870 if (HaveProfile(network_guid)) { | |
871 WLAN_CONNECTION_PARAMETERS wlan_params = { | |
872 wlan_connection_mode_profile, | |
873 profile_name.c_str(), | |
874 NULL, | |
875 NULL, | |
876 dot11_BSS_type_any, | |
877 0}; | |
878 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); | |
879 } else { | |
880 // TODO(mef): wlan_connection_mode_discovery_unsecure is not available on | |
881 // XP. If XP support is needed, then temporary profile will have to be | |
882 // created. | |
883 DOT11_SSID ssid = SSIDFromGUID(network_guid); | |
884 WLAN_CONNECTION_PARAMETERS wlan_params = { | |
885 wlan_connection_mode_discovery_unsecure, | |
886 NULL, | |
887 &ssid, | |
888 NULL, | |
889 dot11_BSS_type_infrastructure, | |
890 0}; | |
891 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); | |
892 } | |
893 | |
894 return error; | |
895 } | |
896 | |
897 DWORD WiFiServiceImpl::Disconnect() { | |
898 if (client_ == NULL) { | |
899 NOTREACHED(); | |
900 return ERROR_NOINTERFACE; | |
901 } | |
902 | |
903 DWORD error = ERROR_SUCCESS; | |
904 error = ::WlanDisconnect(client_, &interface_guid_, NULL); | |
905 return error; | |
906 } | |
907 | |
908 DWORD WiFiServiceImpl::SaveTempProfile(const std::string& network_guid) { | |
909 if (client_ == NULL) { | |
910 NOTREACHED(); | |
911 return ERROR_NOINTERFACE; | |
912 } | |
913 | |
914 DWORD error = ERROR_SUCCESS; | |
915 base::string16 profile_name = ProfileNameFromGUID(network_guid); | |
916 // TODO(mef): WlanSaveTemporaryProfile is not available on XP. If XP support | |
917 // is needed, then different method of saving network profile will have to be | |
918 // used. | |
919 error = ::WlanSaveTemporaryProfile(client_, | |
920 &interface_guid_, | |
921 profile_name.c_str(), | |
922 NULL, | |
923 WLAN_PROFILE_USER, | |
924 true, | |
925 NULL); | |
926 return error; | |
927 } | |
928 | |
929 DWORD WiFiServiceImpl::GetProfile(const std::string& network_guid, | |
930 std::string* profile_xml) { | |
931 if (client_ == NULL) { | |
932 NOTREACHED(); | |
933 return ERROR_NOINTERFACE; | |
934 } | |
935 | |
936 DWORD error = ERROR_SUCCESS; | |
937 base::string16 profile_name = ProfileNameFromGUID(network_guid); | |
938 LPWSTR str_profile_xml = NULL; | |
939 error = ::WlanGetProfile(client_, | |
940 &interface_guid_, | |
941 profile_name.c_str(), | |
942 NULL, | |
943 &str_profile_xml, | |
944 NULL, | |
945 NULL); | |
946 | |
947 if (error == ERROR_SUCCESS && str_profile_xml != NULL) { | |
948 *profile_xml = base::UTF16ToUTF8(str_profile_xml); | |
949 } | |
950 // clean up | |
951 if (str_profile_xml != NULL) { | |
952 ::WlanFreeMemory(str_profile_xml); | |
953 } | |
954 | |
955 return error; | |
956 } | |
957 | |
958 bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) { | |
959 DWORD error = ERROR_SUCCESS; | |
960 std::string profile_xml; | |
961 return GetProfile(network_guid, &profile_xml) == ERROR_SUCCESS; | |
962 } | |
963 | |
964 void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList& networks) { | |
965 if (network_list_changed_observer_.is_null()) | |
966 return; | |
967 | |
968 NetworkGuidList current_networks; | |
969 for (NetworkList::const_iterator it = networks.begin(); | |
970 it != networks.end(); | |
971 ++it) { | |
972 current_networks.push_back(it->guid); | |
973 } | |
974 network_list_changed_observer_.Run(current_networks); | |
975 } | |
976 | |
977 void WiFiServiceImpl::NotifyNetworkChanged(const std::string& network_guid) { | |
978 if (enable_notify_network_changed_ && !networks_changed_observer_.is_null()) { | |
979 DLOG(INFO) << "NotifyNetworkChanged: " << network_guid; | |
980 NetworkGuidList changed_networks(1, network_guid); | |
981 networks_changed_observer_.Run(changed_networks); | |
982 } | |
983 } | |
984 | |
985 WiFiService* WiFiService::CreateService() { return new WiFiServiceImpl(); } | |
986 | |
987 } // namespace wifi | |
OLD | NEW |