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

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

Powered by Google App Engine
This is Rietveld 408576698