OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/wifi/wifi_service.h" | 5 #include "components/wifi/wifi_service.h" |
6 | 6 |
7 #include <iphlpapi.h> | 7 #include <iphlpapi.h> |
8 #include <objbase.h> | 8 #include <objbase.h> |
9 #include <wlanapi.h> | 9 #include <wlanapi.h> |
10 | 10 |
(...skipping 17 matching lines...) Expand all Loading... |
28 const char kWiFiServiceErrorNotImplemented[] = | 28 const char kWiFiServiceErrorNotImplemented[] = |
29 "Error.WiFiService.NotImplemented"; | 29 "Error.WiFiService.NotImplemented"; |
30 const wchar_t kNwCategoryWizardRegKey[] = | 30 const wchar_t kNwCategoryWizardRegKey[] = |
31 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Network\\" | 31 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Network\\" |
32 L"NwCategoryWizard"; | 32 L"NwCategoryWizard"; |
33 const wchar_t kNwCategoryWizardRegValue[] = L"Show"; | 33 const wchar_t kNwCategoryWizardRegValue[] = L"Show"; |
34 const wchar_t kNwCategoryWizardSavedRegValue[] = L"ShowSaved"; | 34 const wchar_t kNwCategoryWizardSavedRegValue[] = L"ShowSaved"; |
35 const wchar_t kNwCategoryWizardDeleteRegValue[] = L"ShowDelete"; | 35 const wchar_t kNwCategoryWizardDeleteRegValue[] = L"ShowDelete"; |
36 const wchar_t kWlanApiDll[] = L"wlanapi.dll"; | 36 const wchar_t kWlanApiDll[] = L"wlanapi.dll"; |
37 | 37 |
| 38 // Created Profile Dictionary keys |
| 39 const char kProfileXmlKey[] = "xml"; |
| 40 const char kProfileSharedKey[] = "shared"; |
| 41 |
38 // WlanApi function names | 42 // WlanApi function names |
39 const char kWlanConnect[] = "WlanConnect"; | 43 const char kWlanConnect[] = "WlanConnect"; |
40 const char kWlanCloseHandle[] = "WlanCloseHandle"; | 44 const char kWlanCloseHandle[] = "WlanCloseHandle"; |
| 45 const char kWlanDeleteProfile[] = "WlanDeleteProfile"; |
41 const char kWlanDisconnect[] = "WlanDisconnect"; | 46 const char kWlanDisconnect[] = "WlanDisconnect"; |
42 const char kWlanEnumInterfaces[] = "WlanEnumInterfaces"; | 47 const char kWlanEnumInterfaces[] = "WlanEnumInterfaces"; |
43 const char kWlanFreeMemory[] = "WlanFreeMemory"; | 48 const char kWlanFreeMemory[] = "WlanFreeMemory"; |
44 const char kWlanGetAvailableNetworkList[] = "WlanGetAvailableNetworkList"; | 49 const char kWlanGetAvailableNetworkList[] = "WlanGetAvailableNetworkList"; |
45 const char kWlanGetNetworkBssList[] = "WlanGetNetworkBssList"; | 50 const char kWlanGetNetworkBssList[] = "WlanGetNetworkBssList"; |
46 const char kWlanGetProfile[] = "WlanGetProfile"; | 51 const char kWlanGetProfile[] = "WlanGetProfile"; |
47 const char kWlanOpenHandle[] = "WlanOpenHandle"; | 52 const char kWlanOpenHandle[] = "WlanOpenHandle"; |
48 const char kWlanQueryInterface[] = "WlanQueryInterface"; | 53 const char kWlanQueryInterface[] = "WlanQueryInterface"; |
49 const char kWlanRegisterNotification[] = "WlanRegisterNotification"; | 54 const char kWlanRegisterNotification[] = "WlanRegisterNotification"; |
50 const char kWlanSaveTemporaryProfile[] = "WlanSaveTemporaryProfile"; | 55 const char kWlanSaveTemporaryProfile[] = "WlanSaveTemporaryProfile"; |
51 const char kWlanScan[] = "WlanScan"; | 56 const char kWlanScan[] = "WlanScan"; |
52 const char kWlanSetProfile[] = "WlanSetProfile"; | 57 const char kWlanSetProfile[] = "WlanSetProfile"; |
53 | 58 |
54 // WlanApi function definitions | 59 // WlanApi function definitions |
55 typedef DWORD (WINAPI* WlanConnectFunction)( | 60 typedef DWORD (WINAPI* WlanConnectFunction)( |
56 HANDLE hClientHandle, | 61 HANDLE hClientHandle, |
57 CONST GUID *pInterfaceGuid, | 62 CONST GUID *pInterfaceGuid, |
58 CONST PWLAN_CONNECTION_PARAMETERS pConnectionParameters, | 63 CONST PWLAN_CONNECTION_PARAMETERS pConnectionParameters, |
59 PVOID pReserved); | 64 PVOID pReserved); |
60 | 65 |
61 typedef DWORD (WINAPI* WlanCloseHandleFunction)( | 66 typedef DWORD (WINAPI* WlanCloseHandleFunction)( |
62 HANDLE hClientHandle, | 67 HANDLE hClientHandle, |
63 PVOID pReserved); | 68 PVOID pReserved); |
64 | 69 |
| 70 typedef DWORD (WINAPI* WlanDeleteProfileFunction)( |
| 71 HANDLE hClientHandle, |
| 72 const GUID *pInterfaceGuid, |
| 73 LPCWSTR strProfileName, |
| 74 PVOID pReserved); |
| 75 |
65 typedef DWORD (WINAPI* WlanDisconnectFunction)( | 76 typedef DWORD (WINAPI* WlanDisconnectFunction)( |
66 HANDLE hClientHandle, | 77 HANDLE hClientHandle, |
67 CONST GUID *pInterfaceGuid, | 78 CONST GUID *pInterfaceGuid, |
68 PVOID pReserved); | 79 PVOID pReserved); |
69 | 80 |
70 typedef DWORD (WINAPI* WlanEnumInterfacesFunction)( | 81 typedef DWORD (WINAPI* WlanEnumInterfacesFunction)( |
71 HANDLE hClientHandle, | 82 HANDLE hClientHandle, |
72 PVOID pReserved, | 83 PVOID pReserved, |
73 PWLAN_INTERFACE_INFO_LIST *ppInterfaceList); | 84 PWLAN_INTERFACE_INFO_LIST *ppInterfaceList); |
74 | 85 |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 std::string* error) OVERRIDE; | 226 std::string* error) OVERRIDE; |
216 | 227 |
217 virtual void SetEventObservers( | 228 virtual void SetEventObservers( |
218 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, | 229 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
219 const NetworkGuidListCallback& networks_changed_observer, | 230 const NetworkGuidListCallback& networks_changed_observer, |
220 const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE; | 231 const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE; |
221 | 232 |
222 virtual void RequestConnectedNetworkUpdate() OVERRIDE {} | 233 virtual void RequestConnectedNetworkUpdate() OVERRIDE {} |
223 | 234 |
224 private: | 235 private: |
| 236 typedef int32 EncryptionType; |
| 237 enum EncryptionTypeEnum { |
| 238 kEncryptionTypeAny = 0, |
| 239 kEncryptionTypeAES = 1, |
| 240 kEncryptionTypeTKIP = 2 |
| 241 }; |
| 242 |
225 // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification | 243 // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification |
226 // on WiFiServiceImpl passed back as |context|. | 244 // on WiFiServiceImpl passed back as |context|. |
227 static void __stdcall OnWlanNotificationCallback( | 245 static void __stdcall OnWlanNotificationCallback( |
228 PWLAN_NOTIFICATION_DATA wlan_notification_data, | 246 PWLAN_NOTIFICATION_DATA wlan_notification_data, |
229 PVOID context); | 247 PVOID context); |
230 | 248 |
231 // Callback for Windows WLAN_NOTIFICATION. Called on random thread from | 249 // Callback for Windows WLAN_NOTIFICATION. Called on random thread from |
232 // OnWlanNotificationCallback. Handles network connectivity and scan complete | 250 // OnWlanNotificationCallback. Handles network connectivity and scan complete |
233 // notification and posts tasks to main thread. | 251 // notification and posts tasks to main thread. |
234 void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data); | 252 void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 } | 324 } |
307 | 325 |
308 // Get unique |network_guid| string based on |wlan|. | 326 // Get unique |network_guid| string based on |wlan|. |
309 std::string GUIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const { | 327 std::string GUIDFromWLAN(const WLAN_AVAILABLE_NETWORK& wlan) const { |
310 return SSIDFromWLAN(wlan); | 328 return SSIDFromWLAN(wlan); |
311 } | 329 } |
312 | 330 |
313 // Deduce |onc::wifi| security from |alg|. | 331 // Deduce |onc::wifi| security from |alg|. |
314 std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const; | 332 std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const; |
315 | 333 |
| 334 // Convert |EncryptionType| into WPA(2) encryption type string. |
| 335 std::string WpaEncryptionFromEncryptionType( |
| 336 EncryptionType encryption_type) const; |
| 337 |
316 // Deduce WLANProfile |authEncryption| values from |onc::wifi| security. | 338 // Deduce WLANProfile |authEncryption| values from |onc::wifi| security. |
317 bool AuthEncryptionFromSecurity(const std::string& security, | 339 bool AuthEncryptionFromSecurity(const std::string& security, |
| 340 EncryptionType encryption_type, |
318 std::string* authentication, | 341 std::string* authentication, |
319 std::string* encryption, | 342 std::string* encryption, |
320 std::string* key_type) const; | 343 std::string* key_type) const; |
321 | 344 |
322 // Populate |properties| based on |wlan| and its corresponding bss info from | 345 // Populate |properties| based on |wlan| and its corresponding bss info from |
323 // |wlan_bss_list|. | 346 // |wlan_bss_list|. |
324 void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan, | 347 void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan, |
325 const WLAN_BSS_LIST& wlan_bss_list, | 348 const WLAN_BSS_LIST& wlan_bss_list, |
326 NetworkProperties* properties); | 349 NetworkProperties* properties); |
327 | 350 |
(...skipping 23 matching lines...) Expand all Loading... |
351 | 374 |
352 // Get DOT11_BSSID_LIST of desired BSSIDs to connect to |ssid| network on | 375 // Get DOT11_BSSID_LIST of desired BSSIDs to connect to |ssid| network on |
353 // given |frequency|. | 376 // given |frequency|. |
354 DWORD GetDesiredBssList(DOT11_SSID& ssid, | 377 DWORD GetDesiredBssList(DOT11_SSID& ssid, |
355 Frequency frequency, | 378 Frequency frequency, |
356 scoped_ptr<DOT11_BSSID_LIST>* desired_list); | 379 scoped_ptr<DOT11_BSSID_LIST>* desired_list); |
357 | 380 |
358 // Normalizes |frequency_in_mhz| into one of |Frequency| values. | 381 // Normalizes |frequency_in_mhz| into one of |Frequency| values. |
359 Frequency GetNormalizedFrequency(int frequency_in_mhz) const; | 382 Frequency GetNormalizedFrequency(int frequency_in_mhz) const; |
360 | 383 |
361 // Create |profile_xml| based on |network_properties|. | 384 // Create |profile_xml| based on |network_properties|. If |encryption_type| |
| 385 // is |kEncryptionTypeAny| applies the type most suitable for parameters in |
| 386 // |network_properties|. |
362 bool CreateProfile(const NetworkProperties& network_properties, | 387 bool CreateProfile(const NetworkProperties& network_properties, |
| 388 EncryptionType encryption_type, |
363 std::string* profile_xml); | 389 std::string* profile_xml); |
364 | 390 |
365 // Save temporary wireless profile for |network_guid|. | 391 // Save temporary wireless profile for |network_guid|. |
366 DWORD SaveTempProfile(const std::string& network_guid); | 392 DWORD SaveTempProfile(const std::string& network_guid); |
367 | 393 |
368 // Get previously stored |profile_xml| for |network_guid|. | 394 // Get previously stored |profile_xml| for |network_guid|. |
369 // If |get_plaintext_key| is true, and process has sufficient privileges, then | 395 // If |get_plaintext_key| is true, and process has sufficient privileges, then |
370 // <sharedKey> data in |profile_xml| will be unprotected. | 396 // <sharedKey> data in |profile_xml| will be unprotected. |
371 DWORD GetProfile(const std::string& network_guid, | 397 DWORD GetProfile(const std::string& network_guid, |
372 bool get_plaintext_key, | 398 bool get_plaintext_key, |
373 std::string* profile_xml); | 399 std::string* profile_xml); |
374 | 400 |
| 401 // Set |profile_xml| to current user or all users depending on |shared| flag. |
| 402 // If |overwrite| is false, then returns an error if profile exists. |
| 403 DWORD SetProfile(bool shared, const std::string& profile_xml, bool overwrite); |
| 404 |
375 // Return true if there is previously stored profile xml for |network_guid|. | 405 // Return true if there is previously stored profile xml for |network_guid|. |
376 bool HaveProfile(const std::string& network_guid); | 406 bool HaveProfile(const std::string& network_guid); |
377 | 407 |
| 408 // Delete profile that was created, but failed to connect. |
| 409 DWORD DeleteCreatedProfile(const std::string& network_guid); |
| 410 |
378 // Notify |network_list_changed_observer_| that list of visible networks has | 411 // Notify |network_list_changed_observer_| that list of visible networks has |
379 // changed to |networks|. | 412 // changed to |networks|. |
380 void NotifyNetworkListChanged(const NetworkList& networks); | 413 void NotifyNetworkListChanged(const NetworkList& networks); |
381 | 414 |
382 // Notify |networks_changed_observer_| that network |network_guid| status has | 415 // Notify |networks_changed_observer_| that network |network_guid| status has |
383 // changed. | 416 // changed. |
384 void NotifyNetworkChanged(const std::string& network_guid); | 417 void NotifyNetworkChanged(const std::string& network_guid); |
385 | 418 |
386 // Load WlanApi.dll from SystemDirectory and get Api function pointers. | 419 // Load WlanApi.dll from SystemDirectory and get Api function pointers. |
387 DWORD LoadWlanLibrary(); | 420 DWORD LoadWlanLibrary(); |
388 // Instance of WlanApi.dll. | 421 // Instance of WlanApi.dll. |
389 HINSTANCE wlan_api_library_; | 422 HINSTANCE wlan_api_library_; |
390 // WlanApi function pointers | 423 // WlanApi function pointers |
391 WlanConnectFunction WlanConnect_function_; | 424 WlanConnectFunction WlanConnect_function_; |
392 WlanCloseHandleFunction WlanCloseHandle_function_; | 425 WlanCloseHandleFunction WlanCloseHandle_function_; |
| 426 WlanDeleteProfileFunction WlanDeleteProfile_function_; |
393 WlanDisconnectFunction WlanDisconnect_function_; | 427 WlanDisconnectFunction WlanDisconnect_function_; |
394 WlanEnumInterfacesFunction WlanEnumInterfaces_function_; | 428 WlanEnumInterfacesFunction WlanEnumInterfaces_function_; |
395 WlanFreeMemoryFunction WlanFreeMemory_function_; | 429 WlanFreeMemoryFunction WlanFreeMemory_function_; |
396 WlanGetAvailableNetworkListFunction WlanGetAvailableNetworkList_function_; | 430 WlanGetAvailableNetworkListFunction WlanGetAvailableNetworkList_function_; |
397 // WlanGetNetworkBssList function may not be avaiable on Windows XP. | 431 // WlanGetNetworkBssList function may not be avaiable on Windows XP. |
398 WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_; | 432 WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_; |
399 WlanGetProfileFunction WlanGetProfile_function_; | 433 WlanGetProfileFunction WlanGetProfile_function_; |
400 WlanOpenHandleFunction WlanOpenHandle_function_; | 434 WlanOpenHandleFunction WlanOpenHandle_function_; |
401 WlanQueryInterfaceFunction WlanQueryInterface_function_; | 435 WlanQueryInterfaceFunction WlanQueryInterface_function_; |
402 WlanRegisterNotificationFunction WlanRegisterNotification_function_; | 436 WlanRegisterNotificationFunction WlanRegisterNotification_function_; |
403 WlanScanFunction WlanScan_function_; | 437 WlanScanFunction WlanScan_function_; |
404 WlanSetProfileFunction WlanSetProfile_function_; | 438 WlanSetProfileFunction WlanSetProfile_function_; |
405 // WlanSaveTemporaryProfile function may not be avaiable on Windows XP. | 439 // WlanSaveTemporaryProfile function may not be avaiable on Windows XP. |
406 WlanSaveTemporaryProfileFunction WlanSaveTemporaryProfile_function_; | 440 WlanSaveTemporaryProfileFunction WlanSaveTemporaryProfile_function_; |
407 | 441 |
408 // WLAN service handle. | 442 // WLAN service handle. |
409 HANDLE client_; | 443 HANDLE client_; |
410 // GUID of the currently connected interface, if any, otherwise the GUID of | 444 // GUID of the currently connected interface, if any, otherwise the GUID of |
411 // one of the WLAN interfaces. | 445 // one of the WLAN interfaces. |
412 GUID interface_guid_; | 446 GUID interface_guid_; |
413 // Temporary storage of network properties indexed by |network_guid|. Persist | 447 // Temporary storage of network properties indexed by |network_guid|. Persist |
414 // only in memory. | 448 // only in memory. |
415 base::DictionaryValue connect_properties_; | 449 base::DictionaryValue connect_properties_; |
416 // Preserved WLAN profile xml. | 450 // Preserved WLAN profile xml. |
417 std::map<std::string, std::string> saved_profiles_xml_; | 451 std::map<std::string, std::string> saved_profiles_xml_; |
| 452 // Created WLAN Profiles, indexed by |network_guid|. Contains xml with TKIP |
| 453 // encryption type saved by |CreateNetwork| if applicable. Profile has to be |
| 454 // deleted if connection fails. Implicitly created profiles have to be deleted |
| 455 // if connection succeeds. Persist only in memory. |
| 456 base::DictionaryValue created_profiles_; |
418 // Observer to get notified when network(s) have changed (e.g. connect). | 457 // Observer to get notified when network(s) have changed (e.g. connect). |
419 NetworkGuidListCallback networks_changed_observer_; | 458 NetworkGuidListCallback networks_changed_observer_; |
420 // Observer to get notified when network list has changed (scan complete). | 459 // Observer to get notified when network list has changed (scan complete). |
421 NetworkGuidListCallback network_list_changed_observer_; | 460 NetworkGuidListCallback network_list_changed_observer_; |
422 // Saved value of network location wizard show value. | 461 // Saved value of network location wizard show value. |
423 scoped_ptr<DWORD> saved_nw_category_wizard_; | 462 scoped_ptr<DWORD> saved_nw_category_wizard_; |
424 // MessageLoopProxy to post events on UI thread. | 463 // MessageLoopProxy to post events on UI thread. |
425 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; | 464 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; |
426 // Task runner for worker tasks. | 465 // Task runner for worker tasks. |
427 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 466 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
428 // If |false|, then |networks_changed_observer_| is not notified. | 467 // If |false|, then |networks_changed_observer_| is not notified. |
429 bool enable_notify_network_changed_; | 468 bool enable_notify_network_changed_; |
430 // Number of attempts to check that network has connected successfully. | 469 // Number of attempts to check that network has connected successfully. |
431 static const int kMaxAttempts = 100; | 470 static const int kMaxAttempts = 100; |
432 // Delay between attempts to check that network has connected successfully. | 471 // Delay between attempts to check that network has connected successfully. |
433 static const int kAttemptDelayMs = 100; | 472 static const int kAttemptDelayMs = 100; |
434 DISALLOW_COPY_AND_ASSIGN(WiFiServiceImpl); | 473 DISALLOW_COPY_AND_ASSIGN(WiFiServiceImpl); |
435 }; | 474 }; |
436 | 475 |
437 WiFiServiceImpl::WiFiServiceImpl() | 476 WiFiServiceImpl::WiFiServiceImpl() |
438 : wlan_api_library_(NULL), | 477 : wlan_api_library_(NULL), |
439 WlanConnect_function_(NULL), | 478 WlanConnect_function_(NULL), |
440 WlanCloseHandle_function_(NULL), | 479 WlanCloseHandle_function_(NULL), |
| 480 WlanDeleteProfile_function_(NULL), |
441 WlanDisconnect_function_(NULL), | 481 WlanDisconnect_function_(NULL), |
442 WlanEnumInterfaces_function_(NULL), | 482 WlanEnumInterfaces_function_(NULL), |
443 WlanFreeMemory_function_(NULL), | 483 WlanFreeMemory_function_(NULL), |
444 WlanGetAvailableNetworkList_function_(NULL), | 484 WlanGetAvailableNetworkList_function_(NULL), |
445 WlanGetNetworkBssList_function_(NULL), | 485 WlanGetNetworkBssList_function_(NULL), |
446 WlanGetProfile_function_(NULL), | 486 WlanGetProfile_function_(NULL), |
447 WlanOpenHandle_function_(NULL), | 487 WlanOpenHandle_function_(NULL), |
448 WlanRegisterNotification_function_(NULL), | 488 WlanRegisterNotification_function_(NULL), |
449 WlanSaveTemporaryProfile_function_(NULL), | 489 WlanSaveTemporaryProfile_function_(NULL), |
450 WlanScan_function_(NULL), | 490 WlanScan_function_(NULL), |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 return; | 569 return; |
530 | 570 |
531 WiFiService::NetworkProperties network_properties; | 571 WiFiService::NetworkProperties network_properties; |
532 if (!network_properties.UpdateFromValue(*properties)) { | 572 if (!network_properties.UpdateFromValue(*properties)) { |
533 CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error); | 573 CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error); |
534 return; | 574 return; |
535 } | 575 } |
536 | 576 |
537 network_properties.guid = network_properties.ssid; | 577 network_properties.guid = network_properties.ssid; |
538 std::string profile_xml; | 578 std::string profile_xml; |
539 if (!CreateProfile(network_properties, &profile_xml)) { | 579 if (!CreateProfile(network_properties, kEncryptionTypeAny, &profile_xml)) { |
540 CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error); | 580 CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error); |
541 return; | 581 return; |
542 } | 582 } |
543 | 583 |
544 base::string16 profile_xml16(base::UTF8ToUTF16(profile_xml)); | 584 error_code = SetProfile(shared, profile_xml, false); |
545 DWORD reason_code = 0u; | |
546 | |
547 error_code = WlanSetProfile_function_(client_, | |
548 &interface_guid_, | |
549 shared ? 0 : WLAN_PROFILE_USER, | |
550 profile_xml16.c_str(), | |
551 NULL, | |
552 FALSE, | |
553 NULL, | |
554 &reason_code); | |
555 if (CheckError(error_code, kWiFiServiceError, error)) { | 585 if (CheckError(error_code, kWiFiServiceError, error)) { |
556 DVLOG(0) << profile_xml; | 586 DVLOG(0) << profile_xml; |
557 DVLOG(0) << "SetProfile Reason Code:" << reason_code; | |
558 return; | 587 return; |
559 } | 588 } |
560 | 589 |
| 590 // WAP and WAP2 networks could use either AES or TKIP encryption type. |
| 591 // Preserve alternative profile to use in case if connection with default |
| 592 // encryption type fails. |
| 593 std::string tkip_profile_xml; |
| 594 if (!CreateProfile(network_properties, |
| 595 kEncryptionTypeTKIP, |
| 596 &tkip_profile_xml)) { |
| 597 CheckError(ERROR_INVALID_DATA, kWiFiServiceError, error); |
| 598 return; |
| 599 } |
| 600 |
| 601 if (tkip_profile_xml != profile_xml) { |
| 602 scoped_ptr<base::DictionaryValue> tkip_profile(new base::DictionaryValue()); |
| 603 tkip_profile->SetString(kProfileXmlKey, tkip_profile_xml); |
| 604 tkip_profile->SetBoolean(kProfileSharedKey, shared); |
| 605 created_profiles_.SetWithoutPathExpansion(network_properties.guid, |
| 606 tkip_profile.release()); |
| 607 } |
| 608 |
561 *network_guid = network_properties.guid; | 609 *network_guid = network_properties.guid; |
562 } | 610 } |
563 | 611 |
564 void WiFiServiceImpl::GetVisibleNetworks(const std::string& network_type, | 612 void WiFiServiceImpl::GetVisibleNetworks(const std::string& network_type, |
565 base::ListValue* network_list) { | 613 base::ListValue* network_list) { |
566 if (!network_type.empty() && | 614 if (!network_type.empty() && |
567 network_type != onc::network_type::kAllTypes && | 615 network_type != onc::network_type::kAllTypes && |
568 network_type != onc::network_type::kWiFi) { | 616 network_type != onc::network_type::kWiFi) { |
569 return; | 617 return; |
570 } | 618 } |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
772 // Get current list of visible networks and notify that network list has | 820 // Get current list of visible networks and notify that network list has |
773 // changed. | 821 // changed. |
774 DWORD error = GetVisibleNetworkList(&networks); | 822 DWORD error = GetVisibleNetworkList(&networks); |
775 DCHECK(error == ERROR_SUCCESS); | 823 DCHECK(error == ERROR_SUCCESS); |
776 if (error == ERROR_SUCCESS) | 824 if (error == ERROR_SUCCESS) |
777 NotifyNetworkListChanged(networks); | 825 NotifyNetworkListChanged(networks); |
778 } | 826 } |
779 | 827 |
780 void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid, | 828 void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid, |
781 int attempt) { | 829 int attempt) { |
782 // If network didn't get connected in |kMaxAttempts|, then restore automatic | 830 // If network didn't get connected in |kMaxAttempts|, then try to connect |
783 // network change notifications and stop waiting. | 831 // using different profile if it was created recently. |
784 if (attempt > kMaxAttempts) { | 832 if (attempt > kMaxAttempts) { |
785 DLOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to " | 833 LOG(ERROR) << kMaxAttempts << " attempts exceeded waiting for connect to " |
786 << network_guid; | 834 << network_guid; |
| 835 |
| 836 base::DictionaryValue* created_profile = NULL; |
| 837 // Check, whether this connection is using newly created profile. |
| 838 if (created_profiles_.GetDictionaryWithoutPathExpansion( |
| 839 network_guid, &created_profile)) { |
| 840 std::string tkip_profile_xml; |
| 841 bool shared = false; |
| 842 // Check, if this connection there is alternative TKIP profile xml that |
| 843 // should be tried. If there is, then set it up and try to connect again. |
| 844 if (created_profile->GetString(kProfileXmlKey, &tkip_profile_xml) && |
| 845 created_profile->GetBoolean(kProfileSharedKey, &shared)) { |
| 846 // Remove TKIP profile xml, so it will not be tried again. |
| 847 created_profile->Remove(kProfileXmlKey, NULL); |
| 848 created_profile->Remove(kProfileSharedKey, NULL); |
| 849 DWORD error_code = SetProfile(shared, tkip_profile_xml, true); |
| 850 if (error_code == ERROR_SUCCESS) { |
| 851 // Try to connect with new profile. |
| 852 error_code = Connect(network_guid, |
| 853 GetFrequencyToConnect(network_guid)); |
| 854 if (error_code == ERROR_SUCCESS) { |
| 855 // Start waiting again. |
| 856 WaitForNetworkConnect(network_guid, 0); |
| 857 return; |
| 858 } else { |
| 859 LOG(ERROR) << "Failed to set created profile for " << network_guid |
| 860 << " error=" << error_code; |
| 861 } |
| 862 } |
| 863 } else { |
| 864 // Connection has failed, so delete bad created profile. |
| 865 DWORD error_code = DeleteCreatedProfile(network_guid); |
| 866 if (error_code != ERROR_SUCCESS) { |
| 867 LOG(ERROR) << "Failed to delete created profile for " << network_guid |
| 868 << " error=" << error_code; |
| 869 } |
| 870 } |
| 871 } |
| 872 // Restore automatic network change notifications and stop waiting. |
787 enable_notify_network_changed_ = true; | 873 enable_notify_network_changed_ = true; |
788 RestoreNwCategoryWizard(); | 874 RestoreNwCategoryWizard(); |
789 return; | 875 return; |
790 } | 876 } |
791 std::string connected_network_guid; | 877 std::string connected_network_guid; |
792 DWORD error = FindConnectedNetwork(&connected_network_guid); | 878 DWORD error = FindConnectedNetwork(&connected_network_guid); |
793 if (network_guid == connected_network_guid) { | 879 if (network_guid == connected_network_guid) { |
794 DVLOG(1) << "WiFi Connected, Reset DHCP: " << network_guid; | 880 DVLOG(1) << "WiFi Connected, Reset DHCP: " << network_guid; |
795 // Even though wireless network is now connected, it may still be unusable, | 881 // Even though wireless network is now connected, it may still be unusable, |
796 // e.g. after Chromecast device reset. Reset DHCP on wireless network to | 882 // e.g. after Chromecast device reset. Reset DHCP on wireless network to |
797 // work around this issue. | 883 // work around this issue. |
798 error = ResetDHCP(); | 884 error = ResetDHCP(); |
| 885 // There is no need to keep created profile as network is connected. |
| 886 created_profiles_.RemoveWithoutPathExpansion(network_guid, NULL); |
799 // Restore previously suppressed notifications. | 887 // Restore previously suppressed notifications. |
800 enable_notify_network_changed_ = true; | 888 enable_notify_network_changed_ = true; |
801 RestoreNwCategoryWizard(); | 889 RestoreNwCategoryWizard(); |
802 NotifyNetworkChanged(network_guid); | 890 NotifyNetworkChanged(network_guid); |
803 } else { | 891 } else { |
804 // Continue waiting for network connection state change. | 892 // Continue waiting for network connection state change. |
805 task_runner_->PostDelayedTask( | 893 task_runner_->PostDelayedTask( |
806 FROM_HERE, | 894 FROM_HERE, |
807 base::Bind(&WiFiServiceImpl::WaitForNetworkConnect, | 895 base::Bind(&WiFiServiceImpl::WaitForNetworkConnect, |
808 base::Unretained(this), | 896 base::Unretained(this), |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 return ERROR_NOT_FOUND; | 958 return ERROR_NOT_FOUND; |
871 } | 959 } |
872 | 960 |
873 // Initialize WlanApi function pointers | 961 // Initialize WlanApi function pointers |
874 WlanConnect_function_ = | 962 WlanConnect_function_ = |
875 reinterpret_cast<WlanConnectFunction>( | 963 reinterpret_cast<WlanConnectFunction>( |
876 ::GetProcAddress(wlan_api_library_, kWlanConnect)); | 964 ::GetProcAddress(wlan_api_library_, kWlanConnect)); |
877 WlanCloseHandle_function_ = | 965 WlanCloseHandle_function_ = |
878 reinterpret_cast<WlanCloseHandleFunction>( | 966 reinterpret_cast<WlanCloseHandleFunction>( |
879 ::GetProcAddress(wlan_api_library_, kWlanCloseHandle)); | 967 ::GetProcAddress(wlan_api_library_, kWlanCloseHandle)); |
| 968 WlanDeleteProfile_function_ = |
| 969 reinterpret_cast<WlanDeleteProfileFunction>( |
| 970 ::GetProcAddress(wlan_api_library_, kWlanDeleteProfile)); |
880 WlanDisconnect_function_ = | 971 WlanDisconnect_function_ = |
881 reinterpret_cast<WlanDisconnectFunction>( | 972 reinterpret_cast<WlanDisconnectFunction>( |
882 ::GetProcAddress(wlan_api_library_, kWlanDisconnect)); | 973 ::GetProcAddress(wlan_api_library_, kWlanDisconnect)); |
883 WlanEnumInterfaces_function_ = | 974 WlanEnumInterfaces_function_ = |
884 reinterpret_cast<WlanEnumInterfacesFunction>( | 975 reinterpret_cast<WlanEnumInterfacesFunction>( |
885 ::GetProcAddress(wlan_api_library_, kWlanEnumInterfaces)); | 976 ::GetProcAddress(wlan_api_library_, kWlanEnumInterfaces)); |
886 WlanFreeMemory_function_ = | 977 WlanFreeMemory_function_ = |
887 reinterpret_cast<WlanFreeMemoryFunction>( | 978 reinterpret_cast<WlanFreeMemoryFunction>( |
888 ::GetProcAddress(wlan_api_library_, kWlanFreeMemory)); | 979 ::GetProcAddress(wlan_api_library_, kWlanFreeMemory)); |
889 WlanGetAvailableNetworkList_function_ = | 980 WlanGetAvailableNetworkList_function_ = |
(...skipping 19 matching lines...) Expand all Loading... |
909 ::GetProcAddress(wlan_api_library_, kWlanSaveTemporaryProfile)); | 1000 ::GetProcAddress(wlan_api_library_, kWlanSaveTemporaryProfile)); |
910 WlanScan_function_ = | 1001 WlanScan_function_ = |
911 reinterpret_cast<WlanScanFunction>( | 1002 reinterpret_cast<WlanScanFunction>( |
912 ::GetProcAddress(wlan_api_library_, kWlanScan)); | 1003 ::GetProcAddress(wlan_api_library_, kWlanScan)); |
913 WlanSetProfile_function_ = | 1004 WlanSetProfile_function_ = |
914 reinterpret_cast<WlanSetProfileFunction>( | 1005 reinterpret_cast<WlanSetProfileFunction>( |
915 ::GetProcAddress(wlan_api_library_, kWlanSetProfile)); | 1006 ::GetProcAddress(wlan_api_library_, kWlanSetProfile)); |
916 | 1007 |
917 if (!WlanConnect_function_ || | 1008 if (!WlanConnect_function_ || |
918 !WlanCloseHandle_function_ || | 1009 !WlanCloseHandle_function_ || |
| 1010 !WlanDeleteProfile_function_ || |
919 !WlanDisconnect_function_ || | 1011 !WlanDisconnect_function_ || |
920 !WlanEnumInterfaces_function_ || | 1012 !WlanEnumInterfaces_function_ || |
921 !WlanFreeMemory_function_ || | 1013 !WlanFreeMemory_function_ || |
922 !WlanGetAvailableNetworkList_function_ || | 1014 !WlanGetAvailableNetworkList_function_ || |
923 !WlanGetProfile_function_ || | 1015 !WlanGetProfile_function_ || |
924 !WlanOpenHandle_function_ || | 1016 !WlanOpenHandle_function_ || |
925 !WlanQueryInterface_function_ || | 1017 !WlanQueryInterface_function_ || |
926 !WlanRegisterNotification_function_ || | 1018 !WlanRegisterNotification_function_ || |
927 !WlanScan_function_ || | 1019 !WlanScan_function_ || |
928 !WlanSetProfile_function_) { | 1020 !WlanSetProfile_function_) { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1081 | 1173 |
1082 DWORD WiFiServiceImpl::CloseClientHandle() { | 1174 DWORD WiFiServiceImpl::CloseClientHandle() { |
1083 DWORD error = ERROR_SUCCESS; | 1175 DWORD error = ERROR_SUCCESS; |
1084 if (client_ != NULL) { | 1176 if (client_ != NULL) { |
1085 error = WlanCloseHandle_function_(client_, NULL); | 1177 error = WlanCloseHandle_function_(client_, NULL); |
1086 client_ = NULL; | 1178 client_ = NULL; |
1087 } | 1179 } |
1088 if (wlan_api_library_ != NULL) { | 1180 if (wlan_api_library_ != NULL) { |
1089 WlanConnect_function_ = NULL; | 1181 WlanConnect_function_ = NULL; |
1090 WlanCloseHandle_function_ = NULL; | 1182 WlanCloseHandle_function_ = NULL; |
| 1183 WlanDeleteProfile_function_ = NULL; |
1091 WlanDisconnect_function_ = NULL; | 1184 WlanDisconnect_function_ = NULL; |
1092 WlanEnumInterfaces_function_ = NULL; | 1185 WlanEnumInterfaces_function_ = NULL; |
1093 WlanFreeMemory_function_ = NULL; | 1186 WlanFreeMemory_function_ = NULL; |
1094 WlanGetAvailableNetworkList_function_ = NULL; | 1187 WlanGetAvailableNetworkList_function_ = NULL; |
1095 WlanGetNetworkBssList_function_ = NULL; | 1188 WlanGetNetworkBssList_function_ = NULL; |
1096 WlanGetProfile_function_ = NULL; | 1189 WlanGetProfile_function_ = NULL; |
1097 WlanOpenHandle_function_ = NULL; | 1190 WlanOpenHandle_function_ = NULL; |
1098 WlanRegisterNotification_function_ = NULL; | 1191 WlanRegisterNotification_function_ = NULL; |
1099 WlanSaveTemporaryProfile_function_ = NULL; | 1192 WlanSaveTemporaryProfile_function_ = NULL; |
1100 WlanScan_function_ = NULL; | 1193 WlanScan_function_ = NULL; |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1460 WLAN_CONNECTION_PARAMETERS wlan_params = { | 1553 WLAN_CONNECTION_PARAMETERS wlan_params = { |
1461 wlan_connection_mode_profile, | 1554 wlan_connection_mode_profile, |
1462 profile_name.c_str(), | 1555 profile_name.c_str(), |
1463 NULL, | 1556 NULL, |
1464 desired_bss_list.get(), | 1557 desired_bss_list.get(), |
1465 dot11_BSS_type_any, | 1558 dot11_BSS_type_any, |
1466 0}; | 1559 0}; |
1467 error = WlanConnect_function_( | 1560 error = WlanConnect_function_( |
1468 client_, &interface_guid_, &wlan_params, NULL); | 1561 client_, &interface_guid_, &wlan_params, NULL); |
1469 } else { | 1562 } else { |
1470 // TODO(mef): wlan_connection_mode_discovery_unsecure is not available on | |
1471 // XP. If XP support is needed, then temporary profile will have to be | |
1472 // created. | |
1473 WLAN_CONNECTION_PARAMETERS wlan_params = { | 1563 WLAN_CONNECTION_PARAMETERS wlan_params = { |
1474 wlan_connection_mode_discovery_unsecure, | 1564 wlan_connection_mode_discovery_unsecure, |
1475 NULL, | 1565 NULL, |
1476 &ssid, | 1566 &ssid, |
1477 desired_bss_list.get(), | 1567 desired_bss_list.get(), |
1478 dot11_BSS_type_infrastructure, | 1568 dot11_BSS_type_infrastructure, |
1479 0}; | 1569 0}; |
1480 error = WlanConnect_function_( | 1570 error = WlanConnect_function_( |
1481 client_, &interface_guid_, &wlan_params, NULL); | 1571 client_, &interface_guid_, &wlan_params, NULL); |
1482 } | 1572 } |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1545 *profile_xml = base::UTF16ToUTF8(str_profile_xml); | 1635 *profile_xml = base::UTF16ToUTF8(str_profile_xml); |
1546 } | 1636 } |
1547 // Clean up. | 1637 // Clean up. |
1548 if (str_profile_xml != NULL) { | 1638 if (str_profile_xml != NULL) { |
1549 WlanFreeMemory_function_(str_profile_xml); | 1639 WlanFreeMemory_function_(str_profile_xml); |
1550 } | 1640 } |
1551 | 1641 |
1552 return error; | 1642 return error; |
1553 } | 1643 } |
1554 | 1644 |
| 1645 DWORD WiFiServiceImpl::SetProfile(bool shared, |
| 1646 const std::string& profile_xml, |
| 1647 bool overwrite) { |
| 1648 DWORD error_code = ERROR_SUCCESS; |
| 1649 |
| 1650 base::string16 profile_xml16(base::UTF8ToUTF16(profile_xml)); |
| 1651 DWORD reason_code = 0u; |
| 1652 |
| 1653 error_code = WlanSetProfile_function_(client_, |
| 1654 &interface_guid_, |
| 1655 shared ? 0 : WLAN_PROFILE_USER, |
| 1656 profile_xml16.c_str(), |
| 1657 NULL, |
| 1658 overwrite, |
| 1659 NULL, |
| 1660 &reason_code); |
| 1661 return error_code; |
| 1662 } |
| 1663 |
1555 bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) { | 1664 bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) { |
1556 DWORD error = ERROR_SUCCESS; | 1665 DWORD error = ERROR_SUCCESS; |
1557 std::string profile_xml; | 1666 std::string profile_xml; |
1558 return GetProfile(network_guid, false, &profile_xml) == ERROR_SUCCESS; | 1667 return GetProfile(network_guid, false, &profile_xml) == ERROR_SUCCESS; |
1559 } | 1668 } |
1560 | 1669 |
| 1670 |
| 1671 DWORD WiFiServiceImpl::DeleteCreatedProfile(const std::string& network_guid) { |
| 1672 base::DictionaryValue* created_profile = NULL; |
| 1673 DWORD error_code = ERROR_SUCCESS; |
| 1674 // Check, whether this connection is using new created profile, and remove it. |
| 1675 if (created_profiles_.GetDictionaryWithoutPathExpansion( |
| 1676 network_guid, &created_profile)) { |
| 1677 // Connection has failed, so delete it. |
| 1678 base::string16 profile_name = ProfileNameFromGUID(network_guid); |
| 1679 error_code = WlanDeleteProfile_function_(client_, |
| 1680 &interface_guid_, |
| 1681 profile_name.c_str(), |
| 1682 NULL); |
| 1683 created_profiles_.RemoveWithoutPathExpansion(network_guid, NULL); |
| 1684 } |
| 1685 return error_code; |
| 1686 } |
| 1687 |
| 1688 std::string WiFiServiceImpl::WpaEncryptionFromEncryptionType( |
| 1689 EncryptionType encryption_type) const { |
| 1690 if (encryption_type == kEncryptionTypeTKIP) |
| 1691 return kEncryptionTKIP; |
| 1692 return kEncryptionAES; |
| 1693 } |
| 1694 |
1561 bool WiFiServiceImpl::AuthEncryptionFromSecurity( | 1695 bool WiFiServiceImpl::AuthEncryptionFromSecurity( |
1562 const std::string& security, | 1696 const std::string& security, |
| 1697 EncryptionType encryption_type, |
1563 std::string* authentication, | 1698 std::string* authentication, |
1564 std::string* encryption, | 1699 std::string* encryption, |
1565 std::string* key_type) const { | 1700 std::string* key_type) const { |
1566 if (security == onc::wifi::kNone) { | 1701 if (security == onc::wifi::kNone) { |
1567 *authentication = kAuthenticationOpen; | 1702 *authentication = kAuthenticationOpen; |
1568 *encryption = kEncryptionNone; | 1703 *encryption = kEncryptionNone; |
1569 } else if (security == onc::wifi::kWEP_PSK) { | 1704 } else if (security == onc::wifi::kWEP_PSK) { |
1570 *authentication = kAuthenticationOpen; | 1705 *authentication = kAuthenticationOpen; |
1571 *encryption = kEncryptionWEP; | 1706 *encryption = kEncryptionWEP; |
1572 *key_type = kKeyTypeNetwork; | 1707 *key_type = kKeyTypeNetwork; |
1573 } else if (security == onc::wifi::kWPA_PSK) { | 1708 } else if (security == onc::wifi::kWPA_PSK) { |
1574 *authentication = kAuthenticationWpaPsk; | 1709 *authentication = kAuthenticationWpaPsk; |
1575 // TODO(mef): WAP |encryption| could be either |AES| or |TKIP|. It has to be | 1710 *encryption = WpaEncryptionFromEncryptionType(encryption_type); |
1576 // determined and adjusted properly during |Connect|. | |
1577 *encryption = kEncryptionAES; | |
1578 *key_type = kKeyTypePassphrase; | 1711 *key_type = kKeyTypePassphrase; |
1579 } else if (security == onc::wifi::kWPA2_PSK) { | 1712 } else if (security == onc::wifi::kWPA2_PSK) { |
1580 *authentication = kAuthenticationWpa2Psk; | 1713 *authentication = kAuthenticationWpa2Psk; |
1581 // TODO(mef): WAP |encryption| could be either |AES| or |TKIP|. It has to be | 1714 *encryption = WpaEncryptionFromEncryptionType(encryption_type); |
1582 // determined and adjusted properly during |Connect|. | |
1583 *encryption = kEncryptionAES; | |
1584 *key_type = kKeyTypePassphrase; | 1715 *key_type = kKeyTypePassphrase; |
1585 } else { | 1716 } else { |
1586 return false; | 1717 return false; |
1587 } | 1718 } |
1588 return true; | 1719 return true; |
1589 } | 1720 } |
1590 | 1721 |
1591 bool WiFiServiceImpl::CreateProfile( | 1722 bool WiFiServiceImpl::CreateProfile( |
1592 const NetworkProperties& network_properties, | 1723 const NetworkProperties& network_properties, |
| 1724 EncryptionType encryption_type, |
1593 std::string* profile_xml) { | 1725 std::string* profile_xml) { |
1594 // Get authentication and encryption values from security. | 1726 // Get authentication and encryption values from security. |
1595 std::string authentication; | 1727 std::string authentication; |
1596 std::string encryption; | 1728 std::string encryption; |
1597 std::string key_type; | 1729 std::string key_type; |
1598 bool valid = AuthEncryptionFromSecurity(network_properties.security, | 1730 bool valid = AuthEncryptionFromSecurity(network_properties.security, |
| 1731 encryption_type, |
1599 &authentication, | 1732 &authentication, |
1600 &encryption, | 1733 &encryption, |
1601 &key_type); | 1734 &key_type); |
1602 if (!valid) | 1735 if (!valid) |
1603 return valid; | 1736 return valid; |
1604 | 1737 |
1605 // Generate profile XML. | 1738 // Generate profile XML. |
1606 XmlWriter xml_writer; | 1739 XmlWriter xml_writer; |
1607 xml_writer.StartWriting(); | 1740 xml_writer.StartWriting(); |
1608 xml_writer.StartElement("WLANProfile"); | 1741 xml_writer.StartElement("WLANProfile"); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1662 NetworkGuidList changed_networks(1, network_guid); | 1795 NetworkGuidList changed_networks(1, network_guid); |
1663 message_loop_proxy_->PostTask( | 1796 message_loop_proxy_->PostTask( |
1664 FROM_HERE, | 1797 FROM_HERE, |
1665 base::Bind(networks_changed_observer_, changed_networks)); | 1798 base::Bind(networks_changed_observer_, changed_networks)); |
1666 } | 1799 } |
1667 } | 1800 } |
1668 | 1801 |
1669 WiFiService* WiFiService::Create() { return new WiFiServiceImpl(); } | 1802 WiFiService* WiFiService::Create() { return new WiFiServiceImpl(); } |
1670 | 1803 |
1671 } // namespace wifi | 1804 } // namespace wifi |
OLD | NEW |