Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: chrome/utility/wifi/wifi_service_win.cc

Issue 27722003: Windows-specific implementation of Networking Private API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Use GetProcAddress to get WlanGetNetworkBssList function to avoid XP issues. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698