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

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

Issue 22295002: Base infrastructure for Networking Private API on Windows and Mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Reset DHCP after WiFi Connect to speed up the connection after factory reset. Created 7 years, 3 months 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/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
18 // TODO(mef): Verify that wlanapi.dll is delay loaded.
19 #pragma comment(lib, "Wlanapi.lib")
20
21 class WiFiServiceImpl : public WiFiService {
22 public:
23 WiFiServiceImpl() : client_(NULL) {
24 OpenClientHandle();
25 }
26
27 virtual ~WiFiServiceImpl() { CloseClientHandle(); }
28
29 virtual void GetProperties(const std::string& network_guid,
30 const NetworkPropertiesCallback& callback,
31 const ErrorCallback& error_callback) {
32 DWORD error = CheckClientHandle();
33
34 if (error == ERROR_SUCCESS) {
35 NetworkList network_list;
36 error = GetVisibleNetworkList(&network_list);
37 if (error == ERROR_SUCCESS && !network_list.empty()) {
38 NetworkList::iterator it = FindNetwork(network_list, network_guid);
39 if (it != network_list.end())
40 callback.Run(network_guid, *it);
41 else
42 error = ERROR_NOT_FOUND;
43 }
44 }
45
46 CheckError(error_callback, "Error.DBusFailed", error);
47 }
48
49 virtual void GetState(const std::string& network_guid,
50 const NetworkPropertiesCallback& callback,
51 const ErrorCallback& error_callback) OVERRIDE {}
52
53 virtual void GetManagedProperties(
54 const std::string& network_guid,
55 const DictionaryResultCallback& callback,
56 const ErrorCallback& error_callback) OVERRIDE {}
57
58 virtual void SetProperties(const std::string& network_guid,
59 const base::DictionaryValue& properties,
60 const StringResultCallback& callback,
61 const ErrorCallback& error_callback) OVERRIDE {}
62
63 virtual void GetVisibleNetworks(
64 const NetworkListCallback& callback,
65 const ErrorCallback& error_callback) OVERRIDE {
66 DWORD error = CheckClientHandle();
67
68 if (error == ERROR_SUCCESS) {
69 NetworkList network_list;
70 error = GetVisibleNetworkList(&network_list);
71 if (error == ERROR_SUCCESS && !network_list.empty()) {
72 SortNetworks(network_list);
73 callback.Run(network_list);
74 }
75 }
76
77 CheckError(error_callback, "Error.DBusFailed", error);
78 }
79
80 virtual void RequestNetworkScan() OVERRIDE {
81 DWORD error = CheckClientHandle();
82 if (error == ERROR_SUCCESS) {
83 WlanScan(client_, &interface_guid_, NULL, NULL, NULL);
84 }
85 }
86
87 virtual void StartConnect(const std::string& network_guid,
88 const StringResultCallback& callback,
89 const ErrorCallback& error_callback) OVERRIDE {
90 DWORD error = CheckClientHandle();
91 if (error == ERROR_SUCCESS) {
92 std::string connected_network_guid;
93 error = SaveCurrentConnectedNetwork(&connected_network_guid);
94 if (error == ERROR_SUCCESS) {
95 error = Connect(network_guid);
96 if (error == ERROR_SUCCESS) {
97 callback.Run(network_guid);
98 // Notify that previously connected network has changed.
99 NotifyNetworkChanged(connected_network_guid);
100 // Start waiting for network connection state change.
101 if (!networks_changed_observer_.is_null())
102 WaitForNetworkConnect(network_guid, 0);
103 }
104 }
105 }
106 CheckError(error_callback, "Error.DBusFailed", error);
107 }
108
109 virtual void StartDisconnect(const std::string& network_guid,
110 const StringResultCallback& callback,
111 const ErrorCallback& error_callback) OVERRIDE {
112 DWORD error = CheckClientHandle();
113
114 if (error == ERROR_SUCCESS) {
115 std::string connected_network_guid;
116 error = SaveCurrentConnectedNetwork(&connected_network_guid);
117 if (error == ERROR_SUCCESS && network_guid == connected_network_guid) {
118 error = Disconnect();
119 if (error == ERROR_SUCCESS) {
120 callback.Run(network_guid);
121 }
122 }
123 }
124 CheckError(error_callback, "Error.DBusFailed", error);
125 }
126
127 virtual void SetNetworksChangedObserver(
128 const NetworkGuidListCallback& observer) OVERRIDE {
129 networks_changed_observer_ = observer;
130 }
131
132 virtual void SetNetworkListChangedObserver(
133 const NetworkGuidListCallback& observer) OVERRIDE {
134 network_list_changed_observer_ = observer;
135 }
136
137 private:
138 static void __stdcall OnWlanNotificationCallback(
139 PWLAN_NOTIFICATION_DATA wlan_notification_data,
140 PVOID context) {
141 WiFiServiceImpl* service = reinterpret_cast<WiFiServiceImpl*>(context);
142 service->OnWlanNotification(wlan_notification_data);
143 }
144
145 void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data) {
146 PWLAN_CONNECTION_NOTIFICATION_DATA wlan_connection_data =
147 reinterpret_cast<PWLAN_CONNECTION_NOTIFICATION_DATA>(
148 wlan_notification_data->pData);
149
150 switch (wlan_notification_data->NotificationCode) {
151 case wlan_notification_acm_disconnected:
152 case wlan_notification_acm_connection_complete:
153 // TODO(mef): Figure out how to send notifications correctly from here.
154 // NotifyNetworkChanged(GuidFromSsid(wlan_connection_data->dot11Ssid));
155 break;
156 case wlan_notification_acm_connection_attempt_fail:
157 break;
158 case wlan_notification_acm_scan_complete:
159 break;
160 }
161 }
162
163 void WaitForNetworkConnect(const std::string& network_guid, int attempt) {
164 if (attempt > kMaxAttempts)
165 return;
166
167 std::string connected_network_guid;
168 DWORD error = FindConnectedNetwork(&connected_network_guid);
169 if (network_guid == connected_network_guid) {
170 // Reset DHCP to speed up the connection after Chromekey factory reset.
171 error = ResetDHCP();
172 NotifyNetworkChanged(network_guid);
173 } else {
174 // Continue waiting for network connection state change.
175 base::MessageLoop::current()->PostDelayedTask(
176 FROM_HERE,
177 base::Bind(&WiFiServiceImpl::WaitForNetworkConnect,
178 base::Unretained(this),
179 network_guid,
180 ++attempt),
181 base::TimeDelta::FromMilliseconds(kAttemptDelayMs));
182 }
183 }
184
185 bool CheckError(const ErrorCallback& error_callback,
186 const std::string& error_name,
187 DWORD error_code) {
188 if (error_code != ERROR_SUCCESS) {
189 scoped_ptr<base::DictionaryValue> error_data(new base::DictionaryValue);
190 error_data->SetInteger("Win32ErrorCode", error_code);
191 error_callback.Run(error_name, error_data.Pass());
192 return true;
193 }
194 return false;
195 }
196
197 NetworkList::iterator FindNetwork(NetworkList& networks,
198 const std::string& network_guid) {
199 for (NetworkList::iterator it = networks.begin(); it != networks.end();
200 ++it) {
201 if (it->guid == network_guid)
202 return it;
203 }
204 return networks.end();
205 }
206
207 DWORD SaveCurrentConnectedNetwork(std::string* connected_network_guid) {
208 // Find currently connected network.
209 DWORD error = FindConnectedNetwork(connected_network_guid);
210 if (error == ERROR_SUCCESS && !connected_network_guid->empty()) {
211 if (error == ERROR_SUCCESS) {
212 SaveTempProfile(*connected_network_guid);
213 std::string profile_xml;
214 error = GetProfile(*connected_network_guid, &profile_xml);
215 if (error == ERROR_SUCCESS) {
216 saved_profiles_xml_[*connected_network_guid] = profile_xml;
217 }
218 }
219 }
220 return error;
221 }
222
223 void SortNetworks(NetworkList& networks) {
224 // Sort networks, so connected/connecting is up front, then by type:
225 // Ethernet, WiFi, Cellular, VPN
226 networks.sort(WiFiService::NetworkProperties::OrderByType);
227 }
228
229 // open a WLAN client handle
230 DWORD OpenClientHandle() {
231 CloseClientHandle();
232
233 DWORD error = ERROR_SUCCESS;
234 DWORD service_version = 0;
235
236 // open a handle to the service
237 error = WlanOpenHandle(WLAN_API_VERSION, NULL, &service_version, &client_);
238
239 PWLAN_INTERFACE_INFO_LIST pIntfList = NULL;
240 UINT i = 0;
241
242 if (error == ERROR_SUCCESS) {
243 // enumerate wireless interfaces
244 error = WlanEnumInterfaces(client_, NULL, &pIntfList);
245 if (error == ERROR_SUCCESS) {
246 if (pIntfList != NULL && pIntfList->dwNumberOfItems != 0) {
247 // Use first interface.
248 interface_guid_ = pIntfList->InterfaceInfo[0].InterfaceGuid;
249 WlanRegisterNotification(client_,
250 WLAN_NOTIFICATION_SOURCE_ALL,
251 FALSE,
252 OnWlanNotificationCallback,
253 this,
254 NULL,
255 NULL);
256 } else {
257 error = ERROR_NOINTERFACE;
258 }
259 }
260 // clean up
261 if (pIntfList != NULL)
262 WlanFreeMemory(pIntfList);
263 }
264 return error;
265 }
266
267 DWORD ResetDHCP() {
268 IP_ADAPTER_INDEX_MAP adapter_index_map = {0};
269 DWORD error = FindAdapterIndexMapByGuid(interface_guid_,
270 &adapter_index_map);
271 if (error == ERROR_SUCCESS) {
272 error = IpReleaseAddress(&adapter_index_map);
273 if (error == ERROR_SUCCESS) {
274 error = IpRenewAddress(&adapter_index_map);
275 }
276 }
277 return error;
278 }
279
280 DWORD FindAdapterIndexMapByGuid(const GUID& interface_guid,
281 IP_ADAPTER_INDEX_MAP* adapter_index_map) {
282 string16 guid_string;
283 const int kGUIDSize = 39;
284 ::StringFromGUID2(interface_guid, WriteInto(&guid_string, kGUIDSize),
285 kGUIDSize);
286
287 ULONG buffer_length = 0;
288 DWORD error = GetInterfaceInfo(NULL, &buffer_length);
289 if (error == ERROR_INSUFFICIENT_BUFFER) {
290 scoped_ptr<unsigned char[]> buffer(new unsigned char[buffer_length]);
291 IP_INTERFACE_INFO* interface_info =
292 reinterpret_cast<IP_INTERFACE_INFO*>(buffer.get());
293 error = GetInterfaceInfo(interface_info, &buffer_length);
294 if (error == ERROR_SUCCESS) {
295 for (long adapter = 0; adapter < interface_info->NumAdapters;
296 ++adapter) {
297 if (EndsWith(interface_info->Adapter[adapter].Name, guid_string,
298 false)) {
299 *adapter_index_map = interface_info->Adapter[adapter];
300 break;
301 }
302 }
303 }
304 }
305
306 return error;
307 }
308
309
310 DWORD CheckClientHandle() {
311 if (client_ != NULL)
312 return ERROR_SUCCESS;
313 return OpenClientHandle();
314 }
315
316 DWORD CloseClientHandle() {
317 DWORD error = ERROR_SUCCESS;
318 if (client_ != NULL) {
319 WlanCloseHandle(client_, NULL);
320 client_ = NULL;
321 }
322 return error;
323 }
324
325 base::string16 ProfileNameFromGuid(const std::string& network_guid) const {
326 return base::UTF8ToUTF16(network_guid);
327 }
328
329 DOT11_SSID SsidFromGuid(const std::string& network_guid) const {
330 DOT11_SSID ssid = {0};
331 if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) {
332 ssid.uSSIDLength = network_guid.length();
333 strncpy(reinterpret_cast<char*>(ssid.ucSSID),
334 network_guid.c_str(),
335 ssid.uSSIDLength);
336 }
337 return ssid;
338 }
339
340 std::string GuidFromSsid(const DOT11_SSID& dot11Ssid) {
341 return std::string(reinterpret_cast<const char*>(dot11Ssid.ucSSID),
342 dot11Ssid.uSSIDLength);
343 }
344
345 std::string SsidFromWlan(const WLAN_AVAILABLE_NETWORK& wlan) {
346 return GuidFromSsid(wlan.dot11Ssid);
347 }
348
349
350 std::string GuidFromWlan(const WLAN_AVAILABLE_NETWORK& wlan) {
351 return SsidFromWlan(wlan);
352 }
353
354 WiFiService::Security SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) {
355 // TODO(mef): Figure out correct mapping.
356 switch (alg) {
357 case DOT11_AUTH_ALGO_RSNA:
358 return kSecurityWPA;
359 case DOT11_AUTH_ALGO_RSNA_PSK:
360 return kSecurityWPA_PSK;
361 case DOT11_AUTH_ALGO_80211_SHARED_KEY:
362 return kSecurityWEP_PSK;
363 case DOT11_AUTH_ALGO_80211_OPEN:
364 return kSecurityNone;
365 default:
366 return kSecurityUnknown;
367 }
368 return kSecurityUnknown;
369 }
370
371 void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan,
372 const WLAN_BSS_LIST& wlan_bss_list,
373 NetworkProperties* properties) {
374 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) {
375 properties->connection_state = WiFiService::kConnectionStateConnected;
376 } else {
377 properties->connection_state = WiFiService::kConnectionStateNotConnected;
378 }
379
380 properties->ssid = SsidFromWlan(wlan);
381 properties->name = properties->ssid;
382 properties->guid = GuidFromWlan(wlan);
383 properties->type = WiFiService::kNetworkTypeWiFi;
384
385 for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) {
386 const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]);
387 if (bss_entry.dot11Ssid.uSSIDLength == wlan.dot11Ssid.uSSIDLength &&
388 0 == memcmp(bss_entry.dot11Ssid.ucSSID,
389 wlan.dot11Ssid.ucSSID,
390 bss_entry.dot11Ssid.uSSIDLength)) {
391 if (bss_entry.ulChCenterFrequency < 3000000)
392 properties->frequency = kFrequency2400;
393 else
394 properties->frequency = kFrequency5000;
395 properties->frequency_list.push_back(properties->frequency);
396 properties->bssid = WiFiService::NetworkProperties::MacAddressAsString(
397 bss_entry.dot11Bssid);
398 }
399 }
400 properties->frequency_list.sort();
401 properties->frequency_list.unique();
402
403 properties->security =
404 SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm);
405
406 properties->signal_strength = wlan.wlanSignalQuality;
407 }
408
409 // get the list of visible wireless networks
410 DWORD GetVisibleNetworkList(NetworkList* network_list) {
411 DWORD error = ERROR_SUCCESS;
412
413 if (client_ == NULL) {
414 return ERROR_NOINTERFACE;
415 }
416
417 PWLAN_AVAILABLE_NETWORK_LIST pVList = NULL;
418 PWLAN_BSS_LIST pWlanBssList = NULL;
419
420 error = WlanGetAvailableNetworkList(
421 client_, &interface_guid_, 0, NULL, &pVList);
422
423 if (error == ERROR_SUCCESS && NULL != pVList) {
424 error = WlanGetNetworkBssList(client_,
425 &interface_guid_,
426 NULL,
427 dot11_BSS_type_any,
428 FALSE,
429 NULL,
430 &pWlanBssList);
431 if (error == ERROR_SUCCESS && NULL != pWlanBssList) {
432 for (DWORD i = 0; i < pVList->dwNumberOfItems; ++i) {
433 network_list->push_back(NetworkProperties());
434 NetworkPropertiesFromAvailableNetwork(
435 pVList->Network[i], *pWlanBssList, &network_list->back());
436 }
437 }
438 }
439
440 // clean up
441 if (pVList != NULL) {
442 WlanFreeMemory(pVList);
443 }
444 if (pWlanBssList != NULL) {
445 WlanFreeMemory(pWlanBssList);
446 }
447 return error;
448 }
449
450 // Find currently connected network.
451 DWORD FindConnectedNetwork(std::string* connected_network_guid) {
452 DWORD error = ERROR_SUCCESS;
453
454 if (client_ == NULL) {
455 return ERROR_NOINTERFACE;
456 }
457
458 PWLAN_AVAILABLE_NETWORK_LIST pVList = NULL;
459
460 error = WlanGetAvailableNetworkList(
461 client_, &interface_guid_, 0, NULL, &pVList);
462
463 if (error == ERROR_SUCCESS && NULL != pVList) {
464 for (DWORD i = 0; i < pVList->dwNumberOfItems; ++i) {
465 const WLAN_AVAILABLE_NETWORK& wlan = pVList->Network[i];
466 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) {
467 *connected_network_guid = GuidFromWlan(wlan);
468 break;
469 }
470 }
471 }
472
473 // clean up
474 if (pVList != NULL) {
475 WlanFreeMemory(pVList);
476 }
477
478 return error;
479 }
480
481 DWORD Connect(const std::string& network_guid) {
482 DWORD error = ERROR_SUCCESS;
483
484 if (client_ == NULL) {
485 return ERROR_NOINTERFACE;
486 }
487
488 base::string16 profile_name = ProfileNameFromGuid(network_guid);
489
490 if (HaveProfile(network_guid)) {
491 WLAN_CONNECTION_PARAMETERS wlan_params = {
492 wlan_connection_mode_profile, profile_name.c_str(), NULL,
493 NULL, dot11_BSS_type_any, 0};
494 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL);
495 } else {
496 DOT11_SSID ssid = SsidFromGuid(network_guid);
497 WLAN_CONNECTION_PARAMETERS wlan_params = {
498 wlan_connection_mode_discovery_unsecure, NULL, &ssid, NULL,
499 dot11_BSS_type_infrastructure, 0};
500 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL);
501 }
502
503 return error;
504 }
505
506 DWORD Disconnect() {
507 DWORD error = ERROR_SUCCESS;
508
509 if (client_ == NULL) {
510 return ERROR_NOINTERFACE;
511 }
512
513 error = ::WlanDisconnect(client_, &interface_guid_, NULL);
514 return error;
515 }
516
517 DWORD SaveTempProfile(const std::string& network_guid) {
518 DWORD error = ERROR_SUCCESS;
519
520 if (client_ == NULL) {
521 return ERROR_NOINTERFACE;
522 }
523
524 base::string16 profile_name = ProfileNameFromGuid(network_guid);
525
526 error = ::WlanSaveTemporaryProfile(
527 client_, &interface_guid_, profile_name.c_str(), NULL, 0, true, NULL);
528 return error;
529 }
530
531 DWORD GetProfile(const std::string& network_guid, std::string* profile_xml) {
532 DWORD error = ERROR_SUCCESS;
533
534 if (client_ == NULL) {
535 return ERROR_NOINTERFACE;
536 }
537
538 base::string16 profile_name = ProfileNameFromGuid(network_guid);
539 LPWSTR str_profile_xml = NULL;
540 error = ::WlanGetProfile(client_,
541 &interface_guid_,
542 profile_name.c_str(),
543 NULL,
544 &str_profile_xml,
545 NULL,
546 NULL);
547
548 if (error == ERROR_SUCCESS && str_profile_xml != NULL) {
549 *profile_xml = base::UTF16ToUTF8(str_profile_xml);
550 }
551 // clean up
552 if (str_profile_xml != NULL) {
553 WlanFreeMemory(str_profile_xml);
554 }
555
556 return error;
557 }
558
559 bool HaveProfile(const std::string& network_guid) {
560 DWORD error = ERROR_SUCCESS;
561 std::string profile_xml;
562 return GetProfile(network_guid, &profile_xml) == ERROR_SUCCESS;
563 }
564
565 void NotifyNetworkListChanged(const NetworkList& networks) {
566 if (network_list_changed_observer_.is_null())
567 return;
568
569 WiFiService::NetworkGuidList current_networks;
570 for (WiFiService::NetworkList::const_iterator it = networks.begin();
571 it != networks.end();
572 ++it) {
573 current_networks.push_back(it->guid);
574 }
575 network_list_changed_observer_.Run(current_networks);
576 }
577
578 void NotifyNetworkChanged(const std::string& network_guid) {
579 WiFiService::NetworkGuidList changed_networks(1, network_guid);
580 if (!networks_changed_observer_.is_null())
581 networks_changed_observer_.Run(changed_networks);
582 }
583
584 // Wlan Service Handle.
585 HANDLE client_;
586 // Wlan Interface Guid.
587 GUID interface_guid_;
588 // Preserved Wlan Profile Xml.
589 std::map<std::string, std::string> saved_profiles_xml_;
590
591 NetworkGuidListCallback networks_changed_observer_;
592 NetworkGuidListCallback network_list_changed_observer_;
593
594 static const int kMaxAttempts = 100;
595 static const int kAttemptDelayMs = 100;
596 };
597
598 WiFiService* WiFiService::CreateService() { return new WiFiServiceImpl(); }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698