wifi_data_provider_win.cc 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright (c) 2010 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. #include "services/device/geolocation/wifi_data_provider_win.h"
  5. #include <windows.h>
  6. #include <winioctl.h>
  7. #include <wlanapi.h>
  8. #include "base/logging.h"
  9. #include "base/memory/free_deleter.h"
  10. #include "base/memory/ptr_util.h"
  11. #include "base/metrics/histogram_macros.h"
  12. #include "base/strings/utf_string_conversions.h"
  13. #include "base/win/windows_version.h"
  14. #include "services/device/geolocation/wifi_data_provider_common.h"
  15. #include "services/device/geolocation/wifi_data_provider_common_win.h"
  16. #include "services/device/geolocation/wifi_data_provider_handle.h"
  17. namespace device {
  18. namespace {
  19. static const int kDefaultPollingIntervalMs = 10 * 1000; // 10s
  20. static const int kNoChangePollingIntervalMs = 2 * 60 * 1000; // 2 mins
  21. static const int kTwoNoChangePollingIntervalMs = 10 * 60 * 1000; // 10 mins
  22. static const int kNoWifiPollingIntervalMs = 20 * 1000; // 20s
  23. // WlanOpenHandle
  24. typedef DWORD(WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion,
  25. PVOID pReserved,
  26. PDWORD pdwNegotiatedVersion,
  27. PHANDLE phClientHandle);
  28. // WlanEnumInterfaces
  29. typedef DWORD(WINAPI* WlanEnumInterfacesFunction)(
  30. HANDLE hClientHandle,
  31. PVOID pReserved,
  32. PWLAN_INTERFACE_INFO_LIST* ppInterfaceList);
  33. // WlanGetNetworkBssList
  34. typedef DWORD(WINAPI* WlanGetNetworkBssListFunction)(
  35. HANDLE hClientHandle,
  36. const GUID* pInterfaceGuid,
  37. const PDOT11_SSID pDot11Ssid,
  38. DOT11_BSS_TYPE dot11BssType,
  39. BOOL bSecurityEnabled,
  40. PVOID pReserved,
  41. PWLAN_BSS_LIST* ppWlanBssList);
  42. // WlanFreeMemory
  43. typedef VOID(WINAPI* WlanFreeMemoryFunction)(PVOID pMemory);
  44. // WlanCloseHandle
  45. typedef DWORD(WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle,
  46. PVOID pReserved);
  47. // Extracts data for an access point and converts to AccessPointData.
  48. AccessPointData GetNetworkData(const WLAN_BSS_ENTRY& bss_entry) {
  49. AccessPointData access_point_data;
  50. // Currently we get only MAC address, signal strength and SSID.
  51. access_point_data.mac_address = MacAddressAsString16(bss_entry.dot11Bssid);
  52. access_point_data.radio_signal_strength = bss_entry.lRssi;
  53. // bss_entry.dot11Ssid.ucSSID is not null-terminated.
  54. base::UTF8ToUTF16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID),
  55. static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength),
  56. &access_point_data.ssid);
  57. // TODO(steveblock): Is it possible to get the following?
  58. // access_point_data.signal_to_noise
  59. // access_point_data.age
  60. // access_point_data.channel
  61. return access_point_data;
  62. }
  63. // This class encapsulates loading and interacting with wlan_api.dll, which can
  64. // not be loaded statically because it's not available in Server 2008 R2, where
  65. // it must be installed explicitly by the user if and when they wants to use the
  66. // Wireless interface.
  67. // https://www.bonusbits.com/wiki/KB:Wlanapi.dll_missing_on_Windows_Server_2008_R2
  68. class WindowsWlanApi : public WifiDataProviderCommon::WlanApiInterface {
  69. public:
  70. static std::unique_ptr<WindowsWlanApi> Create();
  71. // Takes ownership of the library handle.
  72. explicit WindowsWlanApi(HINSTANCE library);
  73. ~WindowsWlanApi() override;
  74. // WlanApiInterface implementation
  75. bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
  76. private:
  77. bool GetInterfaceDataWLAN(HANDLE wlan_handle,
  78. const GUID& interface_id,
  79. WifiData::AccessPointDataSet* data);
  80. // Handle to the wlanapi.dll library.
  81. HINSTANCE library_;
  82. // Function pointers for WLAN
  83. WlanOpenHandleFunction WlanOpenHandle_function_;
  84. WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
  85. WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_;
  86. WlanFreeMemoryFunction WlanFreeMemory_function_;
  87. WlanCloseHandleFunction WlanCloseHandle_function_;
  88. };
  89. // static
  90. std::unique_ptr<WindowsWlanApi> WindowsWlanApi::Create() {
  91. // Use an absolute path to load the DLL to avoid DLL preloading attacks.
  92. static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll";
  93. wchar_t path[MAX_PATH] = {0};
  94. ExpandEnvironmentStrings(kDLL, path, std::size(path));
  95. HINSTANCE library = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  96. if (!library)
  97. return nullptr;
  98. return std::make_unique<WindowsWlanApi>(library);
  99. }
  100. WindowsWlanApi::WindowsWlanApi(HINSTANCE library) : library_(library) {
  101. DCHECK(library_);
  102. // Extract all methods from |library_|.
  103. WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>(
  104. GetProcAddress(library_, "WlanOpenHandle"));
  105. WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>(
  106. GetProcAddress(library_, "WlanEnumInterfaces"));
  107. WlanGetNetworkBssList_function_ =
  108. reinterpret_cast<WlanGetNetworkBssListFunction>(
  109. GetProcAddress(library_, "WlanGetNetworkBssList"));
  110. WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>(
  111. GetProcAddress(library_, "WlanFreeMemory"));
  112. WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>(
  113. GetProcAddress(library_, "WlanCloseHandle"));
  114. DCHECK(WlanOpenHandle_function_ && WlanEnumInterfaces_function_ &&
  115. WlanGetNetworkBssList_function_ && WlanFreeMemory_function_ &&
  116. WlanCloseHandle_function_);
  117. }
  118. WindowsWlanApi::~WindowsWlanApi() {
  119. FreeLibrary(library_);
  120. }
  121. bool WindowsWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
  122. DCHECK(data);
  123. DWORD negotiated_version;
  124. HANDLE wlan_handle = nullptr;
  125. // Highest WLAN API version supported by the client; pass the lowest. It seems
  126. // that the negotiated version is the Vista version (the highest) irrespective
  127. // of what we pass!
  128. static const int kXpWlanClientVersion = 1;
  129. if ((*WlanOpenHandle_function_)(kXpWlanClientVersion, NULL,
  130. &negotiated_version,
  131. &wlan_handle) != ERROR_SUCCESS) {
  132. return false;
  133. }
  134. DCHECK(wlan_handle);
  135. // Get the list of interfaces. WlanEnumInterfaces allocates |interface_list|.
  136. WLAN_INTERFACE_INFO_LIST* interface_list = nullptr;
  137. if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) !=
  138. ERROR_SUCCESS) {
  139. return false;
  140. }
  141. DCHECK(interface_list);
  142. // Go through the list of interfaces and get the data for each.
  143. for (size_t i = 0; i < interface_list->dwNumberOfItems; ++i) {
  144. const WLAN_INTERFACE_INFO interface_info = interface_list->InterfaceInfo[i];
  145. // Skip any interface that is midway through association; the
  146. // WlanGetNetworkBssList function call is known to hang indefinitely
  147. // when it's in this state. https://crbug.com/39300
  148. if (interface_info.isState == wlan_interface_state_associating) {
  149. DLOG(WARNING) << "Skipping wifi scan on adapter " << i << " ("
  150. << interface_info.strInterfaceDescription
  151. << ") in 'associating' state. Repeated occurrences "
  152. "indicates a non-responding adapter.";
  153. continue;
  154. }
  155. GetInterfaceDataWLAN(wlan_handle, interface_info.InterfaceGuid, data);
  156. }
  157. (*WlanFreeMemory_function_)(interface_list);
  158. return (*WlanCloseHandle_function_)(wlan_handle, NULL) == ERROR_SUCCESS;
  159. }
  160. // Appends the data for a single interface to |data|. Returns false for error.
  161. bool WindowsWlanApi::GetInterfaceDataWLAN(const HANDLE wlan_handle,
  162. const GUID& interface_id,
  163. WifiData::AccessPointDataSet* data) {
  164. // WlanGetNetworkBssList allocates |bss_list|.
  165. WLAN_BSS_LIST* bss_list = nullptr;
  166. if ((*WlanGetNetworkBssList_function_)(wlan_handle, &interface_id,
  167. NULL, // Use all SSIDs.
  168. dot11_BSS_type_any,
  169. false, // bSecurityEnabled - unused
  170. NULL, // reserved
  171. &bss_list) != ERROR_SUCCESS) {
  172. return false;
  173. }
  174. // WlanGetNetworkBssList() can return success without filling |bss_list|.
  175. if (!bss_list)
  176. return false;
  177. for (size_t i = 0; i < bss_list->dwNumberOfItems; ++i)
  178. data->insert(GetNetworkData(bss_list->wlanBssEntries[i]));
  179. (*WlanFreeMemory_function_)(bss_list);
  180. return true;
  181. }
  182. } // anonymous namespace
  183. WifiDataProvider* WifiDataProviderHandle::DefaultFactoryFunction() {
  184. return new WifiDataProviderWin();
  185. }
  186. WifiDataProviderWin::WifiDataProviderWin() = default;
  187. WifiDataProviderWin::~WifiDataProviderWin() = default;
  188. std::unique_ptr<WifiDataProviderCommon::WlanApiInterface>
  189. WifiDataProviderWin::CreateWlanApi() {
  190. return WindowsWlanApi::Create();
  191. }
  192. std::unique_ptr<WifiPollingPolicy> WifiDataProviderWin::CreatePollingPolicy() {
  193. return std::make_unique<GenericWifiPollingPolicy<
  194. kDefaultPollingIntervalMs, kNoChangePollingIntervalMs,
  195. kTwoNoChangePollingIntervalMs, kNoWifiPollingIntervalMs>>();
  196. }
  197. } // namespace device