Home | History | Annotate | Download | only in geolocation
      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 
      5 // Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See
      6 // http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP
      7 // Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix)
      8 // also support a limited version of the WLAN API. See
      9 // http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses
     10 // wlanapi.h, which is not part of the SDK used by Gears, so is replicated
     11 // locally using data from the MSDN.
     12 //
     13 // Windows XP from Service Pack 2 onwards supports the Wireless Zero
     14 // Configuration (WZC) programming interface. See
     15 // http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx.
     16 //
     17 // The MSDN recommends that one use the WLAN API where available, and WZC
     18 // otherwise.
     19 //
     20 // However, it seems that WZC fails for some wireless cards. Also, WLAN seems
     21 // not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly
     22 // otherwise.
     23 
     24 #include "content/browser/geolocation/wifi_data_provider_win.h"
     25 
     26 #include <windows.h>
     27 #include <winioctl.h>
     28 #include <wlanapi.h>
     29 
     30 #include "base/metrics/histogram.h"
     31 #include "base/strings/utf_string_conversions.h"
     32 #include "base/win/windows_version.h"
     33 #include "content/browser/geolocation/wifi_data_provider_common.h"
     34 #include "content/browser/geolocation/wifi_data_provider_common_win.h"
     35 
     36 // Taken from ndis.h for WinCE.
     37 #define NDIS_STATUS_INVALID_LENGTH   ((NDIS_STATUS)0xC0010014L)
     38 #define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
     39 
     40 namespace content {
     41 namespace {
     42 // The limits on the size of the buffer used for the OID query.
     43 const int kInitialBufferSize = 2 << 12;  // Good for about 50 APs.
     44 const int kMaximumBufferSize = 2 << 20;  // 2MB
     45 
     46 // Length for generic string buffers passed to Win32 APIs.
     47 const int kStringLength = 512;
     48 
     49 // The time periods, in milliseconds, between successive polls of the wifi data.
     50 const int kDefaultPollingInterval = 10000;  // 10s
     51 const int kNoChangePollingInterval = 120000;  // 2 mins
     52 const int kTwoNoChangePollingInterval = 600000;  // 10 mins
     53 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
     54 
     55 // WlanOpenHandle
     56 typedef DWORD (WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion,
     57                                                PVOID pReserved,
     58                                                PDWORD pdwNegotiatedVersion,
     59                                                PHANDLE phClientHandle);
     60 
     61 // WlanEnumInterfaces
     62 typedef DWORD (WINAPI* WlanEnumInterfacesFunction)(
     63     HANDLE hClientHandle,
     64     PVOID pReserved,
     65     PWLAN_INTERFACE_INFO_LIST* ppInterfaceList);
     66 
     67 // WlanGetNetworkBssList
     68 typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)(
     69     HANDLE hClientHandle,
     70     const GUID* pInterfaceGuid,
     71     const  PDOT11_SSID pDot11Ssid,
     72     DOT11_BSS_TYPE dot11BssType,
     73     BOOL bSecurityEnabled,
     74     PVOID pReserved,
     75     PWLAN_BSS_LIST* ppWlanBssList
     76 );
     77 
     78 // WlanFreeMemory
     79 typedef VOID (WINAPI* WlanFreeMemoryFunction)(PVOID pMemory);
     80 
     81 // WlanCloseHandle
     82 typedef DWORD (WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle,
     83                                                 PVOID pReserved);
     84 
     85 
     86 // Local classes and functions
     87 class WindowsWlanApi : public WifiDataProviderCommon::WlanApiInterface {
     88  public:
     89   virtual ~WindowsWlanApi();
     90   // Factory function. Will return NULL if this API is unavailable.
     91   static WindowsWlanApi* Create();
     92 
     93   // WlanApiInterface
     94   virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
     95 
     96  private:
     97   // Takes ownership of the library handle.
     98   explicit WindowsWlanApi(HINSTANCE library);
     99 
    100   // Loads the required functions from the DLL.
    101   void GetWLANFunctions(HINSTANCE wlan_library);
    102   int GetInterfaceDataWLAN(HANDLE wlan_handle,
    103                            const GUID& interface_id,
    104                            WifiData::AccessPointDataSet* data);
    105 
    106   // Logs number of detected wlan interfaces.
    107   static void LogWlanInterfaceCount(int count);
    108 
    109   // Handle to the wlanapi.dll library.
    110   HINSTANCE library_;
    111 
    112   // Function pointers for WLAN
    113   WlanOpenHandleFunction WlanOpenHandle_function_;
    114   WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
    115   WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_;
    116   WlanFreeMemoryFunction WlanFreeMemory_function_;
    117   WlanCloseHandleFunction WlanCloseHandle_function_;
    118 };
    119 
    120 class WindowsNdisApi : public WifiDataProviderCommon::WlanApiInterface {
    121  public:
    122   virtual ~WindowsNdisApi();
    123   static WindowsNdisApi* Create();
    124 
    125   // WlanApiInterface
    126   virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
    127 
    128  private:
    129   static bool GetInterfacesNDIS(
    130       std::vector<base::string16>* interface_service_names_out);
    131 
    132   // Swaps in content of the vector passed
    133   explicit WindowsNdisApi(std::vector<base::string16>* interface_service_names);
    134 
    135   bool GetInterfaceDataNDIS(HANDLE adapter_handle,
    136                             WifiData::AccessPointDataSet* data);
    137   // NDIS variables.
    138   std::vector<base::string16> interface_service_names_;
    139 
    140   // Remembers scan result buffer size across calls.
    141   int oid_buffer_size_;
    142 };
    143 
    144 // Extracts data for an access point and converts to Gears format.
    145 bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
    146                     AccessPointData* access_point_data);
    147 bool UndefineDosDevice(const base::string16& device_name);
    148 bool DefineDosDeviceIfNotExists(const base::string16& device_name);
    149 HANDLE GetFileHandle(const base::string16& device_name);
    150 // Makes the OID query and returns a Win32 error code.
    151 int PerformQuery(HANDLE adapter_handle,
    152                  BYTE* buffer,
    153                  DWORD buffer_size,
    154                  DWORD* bytes_out);
    155 bool ResizeBuffer(int requested_size, scoped_ptr_malloc<BYTE>* buffer);
    156 // Gets the system directory and appends a trailing slash if not already
    157 // present.
    158 bool GetSystemDirectory(base::string16* path);
    159 }  // namespace
    160 
    161 WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
    162   return new Win32WifiDataProvider();
    163 }
    164 
    165 Win32WifiDataProvider::Win32WifiDataProvider() {
    166 }
    167 
    168 Win32WifiDataProvider::~Win32WifiDataProvider() {
    169 }
    170 
    171 WifiDataProviderCommon::WlanApiInterface* Win32WifiDataProvider::NewWlanApi() {
    172   // Use the WLAN interface if we're on Vista and if it's available. Otherwise,
    173   // use NDIS.
    174   WlanApiInterface* api = WindowsWlanApi::Create();
    175   if (api) {
    176     return api;
    177   }
    178   return WindowsNdisApi::Create();
    179 }
    180 
    181 WifiPollingPolicy* Win32WifiDataProvider::NewPollingPolicy() {
    182   return new GenericWifiPollingPolicy<kDefaultPollingInterval,
    183                                       kNoChangePollingInterval,
    184                                       kTwoNoChangePollingInterval,
    185                                       kNoWifiPollingIntervalMilliseconds>;
    186 }
    187 
    188 // Local classes and functions
    189 namespace {
    190 
    191 // WindowsWlanApi
    192 WindowsWlanApi::WindowsWlanApi(HINSTANCE library)
    193     : library_(library) {
    194   GetWLANFunctions(library_);
    195 }
    196 
    197 WindowsWlanApi::~WindowsWlanApi() {
    198   FreeLibrary(library_);
    199 }
    200 
    201 WindowsWlanApi* WindowsWlanApi::Create() {
    202   if (base::win::GetVersion() < base::win::VERSION_VISTA)
    203     return NULL;
    204   // We use an absolute path to load the DLL to avoid DLL preloading attacks.
    205   base::string16 system_directory;
    206   if (!GetSystemDirectory(&system_directory)) {
    207     return NULL;
    208   }
    209   DCHECK(!system_directory.empty());
    210   base::string16 dll_path = system_directory + L"wlanapi.dll";
    211   HINSTANCE library = LoadLibraryEx(dll_path.c_str(),
    212                                     NULL,
    213                                     LOAD_WITH_ALTERED_SEARCH_PATH);
    214   if (!library) {
    215     return NULL;
    216   }
    217   return new WindowsWlanApi(library);
    218 }
    219 
    220 void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) {
    221   DCHECK(wlan_library);
    222   WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>(
    223       GetProcAddress(wlan_library, "WlanOpenHandle"));
    224   WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>(
    225       GetProcAddress(wlan_library, "WlanEnumInterfaces"));
    226   WlanGetNetworkBssList_function_ =
    227       reinterpret_cast<WlanGetNetworkBssListFunction>(
    228       GetProcAddress(wlan_library, "WlanGetNetworkBssList"));
    229   WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>(
    230       GetProcAddress(wlan_library, "WlanFreeMemory"));
    231   WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>(
    232       GetProcAddress(wlan_library, "WlanCloseHandle"));
    233   DCHECK(WlanOpenHandle_function_ &&
    234          WlanEnumInterfaces_function_ &&
    235          WlanGetNetworkBssList_function_ &&
    236          WlanFreeMemory_function_ &&
    237          WlanCloseHandle_function_);
    238 }
    239 
    240 void WindowsWlanApi::LogWlanInterfaceCount(int count) {
    241   UMA_HISTOGRAM_CUSTOM_COUNTS(
    242       "Net.Wifi.InterfaceCount",
    243       count,
    244       1,
    245       5,
    246       5);
    247 }
    248 
    249 bool WindowsWlanApi::GetAccessPointData(
    250     WifiData::AccessPointDataSet* data) {
    251   DCHECK(data);
    252 
    253   // Get the handle to the WLAN API.
    254   DWORD negotiated_version;
    255   HANDLE wlan_handle = NULL;
    256   // We could be executing on either Windows XP or Windows Vista, so use the
    257   // lower version of the client WLAN API. It seems that the negotiated version
    258   // is the Vista version irrespective of what we pass!
    259   static const int kXpWlanClientVersion = 1;
    260   if ((*WlanOpenHandle_function_)(kXpWlanClientVersion,
    261                                   NULL,
    262                                   &negotiated_version,
    263                                   &wlan_handle) != ERROR_SUCCESS) {
    264     LogWlanInterfaceCount(0);
    265     return false;
    266   }
    267   DCHECK(wlan_handle);
    268 
    269   // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
    270   WLAN_INTERFACE_INFO_LIST* interface_list = NULL;
    271   if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) !=
    272       ERROR_SUCCESS) {
    273     LogWlanInterfaceCount(0);
    274     return false;
    275   }
    276   DCHECK(interface_list);
    277 
    278   LogWlanInterfaceCount(interface_list->dwNumberOfItems);
    279 
    280   // Go through the list of interfaces and get the data for each.
    281   for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) {
    282     // Skip any interface that is midway through association; the
    283     // WlanGetNetworkBssList function call is known to hang indefinitely
    284     // when it's in this state. http://crbug.com/39300
    285     if (interface_list->InterfaceInfo[i].isState ==
    286         wlan_interface_state_associating) {
    287       LOG(WARNING) << "Skipping wifi scan on adapter " << i << " ("
    288                    << interface_list->InterfaceInfo[i].strInterfaceDescription
    289                    << ") in 'associating' state. Repeated occurrences "
    290                       "indicates a non-responding adapter.";
    291       continue;
    292     }
    293     GetInterfaceDataWLAN(wlan_handle,
    294                          interface_list->InterfaceInfo[i].InterfaceGuid,
    295                          data);
    296   }
    297 
    298   // Free interface_list.
    299   (*WlanFreeMemory_function_)(interface_list);
    300 
    301   // Close the handle.
    302   if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) {
    303     return false;
    304   }
    305 
    306   return true;
    307 }
    308 
    309 // Appends the data for a single interface to the data vector. Returns the
    310 // number of access points found, or -1 on error.
    311 int WindowsWlanApi::GetInterfaceDataWLAN(
    312     const HANDLE wlan_handle,
    313     const GUID& interface_id,
    314     WifiData::AccessPointDataSet* data) {
    315   DCHECK(data);
    316 
    317   const base::TimeTicks start_time = base::TimeTicks::Now();
    318 
    319   // WlanGetNetworkBssList allocates bss_list.
    320   WLAN_BSS_LIST* bss_list = NULL;
    321   if ((*WlanGetNetworkBssList_function_)(wlan_handle,
    322                                          &interface_id,
    323                                          NULL,   // Use all SSIDs.
    324                                          dot11_BSS_type_any,
    325                                          false,  // bSecurityEnabled - unused
    326                                          NULL,   // reserved
    327                                          &bss_list) != ERROR_SUCCESS) {
    328     return -1;
    329   }
    330   // According to http://www.attnetclient.com/kb/questions.php?questionid=75
    331   // WlanGetNetworkBssList can sometimes return success, but leave the bss
    332   // list as NULL.
    333   if (!bss_list)
    334     return -1;
    335 
    336   const base::TimeDelta duration = base::TimeTicks::Now() - start_time;
    337 
    338   UMA_HISTOGRAM_CUSTOM_TIMES(
    339       "Net.Wifi.ScanLatency",
    340       duration,
    341       base::TimeDelta::FromMilliseconds(1),
    342       base::TimeDelta::FromMinutes(1),
    343       100);
    344 
    345 
    346   int found = 0;
    347   for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) {
    348     AccessPointData access_point_data;
    349     if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) {
    350       ++found;
    351       data->insert(access_point_data);
    352     }
    353   }
    354 
    355   (*WlanFreeMemory_function_)(bss_list);
    356 
    357   return found;
    358 }
    359 
    360 // WindowsNdisApi
    361 WindowsNdisApi::WindowsNdisApi(
    362     std::vector<base::string16>* interface_service_names)
    363     : oid_buffer_size_(kInitialBufferSize) {
    364   DCHECK(!interface_service_names->empty());
    365   interface_service_names_.swap(*interface_service_names);
    366 }
    367 
    368 WindowsNdisApi::~WindowsNdisApi() {
    369 }
    370 
    371 WindowsNdisApi* WindowsNdisApi::Create() {
    372   std::vector<base::string16> interface_service_names;
    373   if (GetInterfacesNDIS(&interface_service_names)) {
    374     return new WindowsNdisApi(&interface_service_names);
    375   }
    376   return NULL;
    377 }
    378 
    379 bool WindowsNdisApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
    380   DCHECK(data);
    381   int interfaces_failed = 0;
    382   int interfaces_succeeded = 0;
    383 
    384   for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) {
    385     // First, check that we have a DOS device for this adapter.
    386     if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) {
    387       continue;
    388     }
    389 
    390     // Get the handle to the device. This will fail if the named device is not
    391     // valid.
    392     HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]);
    393     if (adapter_handle == INVALID_HANDLE_VALUE) {
    394       continue;
    395     }
    396 
    397     // Get the data.
    398     if (GetInterfaceDataNDIS(adapter_handle, data)) {
    399       ++interfaces_succeeded;
    400     } else {
    401       ++interfaces_failed;
    402     }
    403 
    404     // Clean up.
    405     CloseHandle(adapter_handle);
    406     UndefineDosDevice(interface_service_names_[i]);
    407   }
    408 
    409   // Return true if at least one interface succeeded, or at the very least none
    410   // failed.
    411   return interfaces_succeeded > 0 || interfaces_failed == 0;
    412 }
    413 
    414 bool WindowsNdisApi::GetInterfacesNDIS(
    415     std::vector<base::string16>* interface_service_names_out) {
    416   HKEY network_cards_key = NULL;
    417   if (RegOpenKeyEx(
    418       HKEY_LOCAL_MACHINE,
    419       L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
    420       0,
    421       KEY_READ,
    422       &network_cards_key) != ERROR_SUCCESS) {
    423     return false;
    424   }
    425   DCHECK(network_cards_key);
    426 
    427   for (int i = 0; ; ++i) {
    428     TCHAR name[kStringLength];
    429     DWORD name_size = kStringLength;
    430     FILETIME time;
    431     if (RegEnumKeyEx(network_cards_key,
    432                      i,
    433                      name,
    434                      &name_size,
    435                      NULL,
    436                      NULL,
    437                      NULL,
    438                      &time) != ERROR_SUCCESS) {
    439       break;
    440     }
    441     HKEY hardware_key = NULL;
    442     if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) !=
    443         ERROR_SUCCESS) {
    444       break;
    445     }
    446     DCHECK(hardware_key);
    447 
    448     TCHAR service_name[kStringLength];
    449     DWORD service_name_size = kStringLength;
    450     DWORD type = 0;
    451     if (RegQueryValueEx(hardware_key,
    452                         L"ServiceName",
    453                         NULL,
    454                         &type,
    455                         reinterpret_cast<LPBYTE>(service_name),
    456                         &service_name_size) == ERROR_SUCCESS) {
    457       interface_service_names_out->push_back(service_name);
    458     }
    459     RegCloseKey(hardware_key);
    460   }
    461 
    462   RegCloseKey(network_cards_key);
    463   return true;
    464 }
    465 
    466 
    467 bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle,
    468                                           WifiData::AccessPointDataSet* data) {
    469   DCHECK(data);
    470 
    471   scoped_ptr_malloc<BYTE> buffer(
    472       reinterpret_cast<BYTE*>(malloc(oid_buffer_size_)));
    473   if (buffer == NULL) {
    474     return false;
    475   }
    476 
    477   DWORD bytes_out;
    478   int result;
    479 
    480   while (true) {
    481     bytes_out = 0;
    482     result = PerformQuery(adapter_handle, buffer.get(),
    483                           oid_buffer_size_, &bytes_out);
    484     if (result == ERROR_GEN_FAILURE ||  // Returned by some Intel cards.
    485         result == ERROR_INSUFFICIENT_BUFFER ||
    486         result == ERROR_MORE_DATA ||
    487         result == NDIS_STATUS_INVALID_LENGTH ||
    488         result == NDIS_STATUS_BUFFER_TOO_SHORT) {
    489       // The buffer we supplied is too small, so increase it. bytes_out should
    490       // provide the required buffer size, but this is not always the case.
    491       if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) {
    492         oid_buffer_size_ = bytes_out;
    493       } else {
    494         oid_buffer_size_ *= 2;
    495       }
    496       if (!ResizeBuffer(oid_buffer_size_, &buffer)) {
    497         oid_buffer_size_ = kInitialBufferSize;  // Reset for next time.
    498         return false;
    499       }
    500     } else {
    501       // The buffer is not too small.
    502       break;
    503     }
    504   }
    505   DCHECK(buffer.get());
    506 
    507   if (result == ERROR_SUCCESS) {
    508     NDIS_802_11_BSSID_LIST* bssid_list =
    509         reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer.get());
    510     GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data);
    511   }
    512 
    513   return true;
    514 }
    515 
    516 bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
    517                     AccessPointData* access_point_data) {
    518   // Currently we get only MAC address, signal strength and SSID.
    519   DCHECK(access_point_data);
    520   access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid);
    521   access_point_data->radio_signal_strength = bss_entry.lRssi;
    522   // bss_entry.dot11Ssid.ucSSID is not null-terminated.
    523   UTF8ToUTF16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID),
    524               static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength),
    525               &access_point_data->ssid);
    526   // TODO(steveblock): Is it possible to get the following?
    527   // access_point_data->signal_to_noise
    528   // access_point_data->age
    529   // access_point_data->channel
    530   return true;
    531 }
    532 
    533 bool UndefineDosDevice(const base::string16& device_name) {
    534   // We remove only the mapping we use, that is \Device\<device_name>.
    535   base::string16 target_path = L"\\Device\\" + device_name;
    536   return DefineDosDevice(
    537       DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
    538       device_name.c_str(),
    539       target_path.c_str()) == TRUE;
    540 }
    541 
    542 bool DefineDosDeviceIfNotExists(const base::string16& device_name) {
    543   // We create a DOS device name for the device at \Device\<device_name>.
    544   base::string16 target_path = L"\\Device\\" + device_name;
    545 
    546   TCHAR target[kStringLength];
    547   if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
    548       target_path.compare(target) == 0) {
    549     // Device already exists.
    550     return true;
    551   }
    552 
    553   if (GetLastError() != ERROR_FILE_NOT_FOUND) {
    554     return false;
    555   }
    556 
    557   if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
    558                        device_name.c_str(),
    559                        target_path.c_str())) {
    560     return false;
    561   }
    562 
    563   // Check that the device is really there.
    564   return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
    565       target_path.compare(target) == 0;
    566 }
    567 
    568 HANDLE GetFileHandle(const base::string16& device_name) {
    569   // We access a device with DOS path \Device\<device_name> at
    570   // \\.\<device_name>.
    571   base::string16 formatted_device_name = L"\\\\.\\" + device_name;
    572 
    573   return CreateFile(formatted_device_name.c_str(),
    574                     GENERIC_READ,
    575                     FILE_SHARE_READ | FILE_SHARE_WRITE,  // share mode
    576                     0,  // security attributes
    577                     OPEN_EXISTING,
    578                     0,  // flags and attributes
    579                     INVALID_HANDLE_VALUE);
    580 }
    581 
    582 int PerformQuery(HANDLE adapter_handle,
    583                  BYTE* buffer,
    584                  DWORD buffer_size,
    585                  DWORD* bytes_out) {
    586   DWORD oid = OID_802_11_BSSID_LIST;
    587   if (!DeviceIoControl(adapter_handle,
    588                        IOCTL_NDIS_QUERY_GLOBAL_STATS,
    589                        &oid,
    590                        sizeof(oid),
    591                        buffer,
    592                        buffer_size,
    593                        bytes_out,
    594                        NULL)) {
    595     return GetLastError();
    596   }
    597   return ERROR_SUCCESS;
    598 }
    599 
    600 bool ResizeBuffer(int requested_size, scoped_ptr_malloc<BYTE>* buffer) {
    601   DCHECK_GT(requested_size, 0);
    602   DCHECK(buffer);
    603   if (requested_size > kMaximumBufferSize) {
    604     buffer->reset();
    605     return false;
    606   }
    607 
    608   buffer->reset(reinterpret_cast<BYTE*>(
    609       realloc(buffer->release(), requested_size)));
    610   return buffer != NULL;
    611 }
    612 
    613 bool GetSystemDirectory(base::string16* path) {
    614   DCHECK(path);
    615   // Return value includes terminating NULL.
    616   int buffer_size = ::GetSystemDirectory(NULL, 0);
    617   if (buffer_size == 0) {
    618     return false;
    619   }
    620   scoped_ptr<char16[]> buffer(new char16[buffer_size]);
    621 
    622   // Return value excludes terminating NULL.
    623   int characters_written = ::GetSystemDirectory(buffer.get(), buffer_size);
    624   if (characters_written == 0) {
    625     return false;
    626   }
    627   DCHECK_EQ(buffer_size - 1, characters_written);
    628 
    629   path->assign(buffer.get(), characters_written);
    630 
    631   if (*path->rbegin() != L'\\') {
    632     path->append(L"\\");
    633   }
    634   DCHECK_EQ(L'\\', *path->rbegin());
    635   return true;
    636 }
    637 }  // namespace
    638 
    639 }  // namespace content
    640