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<string16>* interface_service_names_out);
    131 
    132   // Swaps in content of the vector passed
    133   explicit WindowsNdisApi(std::vector<string16>* interface_service_names);
    134 
    135   bool GetInterfaceDataNDIS(HANDLE adapter_handle,
    136                             WifiData::AccessPointDataSet* data);
    137   // NDIS variables.
    138   std::vector<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 string16& device_name);
    148 bool DefineDosDeviceIfNotExists(const string16& device_name);
    149 HANDLE GetFileHandle(const 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(string16* path);
    159 }  // namespace
    160 
    161 template<>
    162 WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
    163   return new Win32WifiDataProvider();
    164 }
    165 
    166 Win32WifiDataProvider::Win32WifiDataProvider() {
    167 }
    168 
    169 Win32WifiDataProvider::~Win32WifiDataProvider() {
    170 }
    171 
    172 WifiDataProviderCommon::WlanApiInterface* Win32WifiDataProvider::NewWlanApi() {
    173   // Use the WLAN interface if we're on Vista and if it's available. Otherwise,
    174   // use NDIS.
    175   WlanApiInterface* api = WindowsWlanApi::Create();
    176   if (api) {
    177     return api;
    178   }
    179   return WindowsNdisApi::Create();
    180 }
    181 
    182 PollingPolicyInterface* Win32WifiDataProvider::NewPollingPolicy() {
    183   return new GenericPollingPolicy<kDefaultPollingInterval,
    184                                   kNoChangePollingInterval,
    185                                   kTwoNoChangePollingInterval,
    186                                   kNoWifiPollingIntervalMilliseconds>;
    187 }
    188 
    189 // Local classes and functions
    190 namespace {
    191 
    192 // WindowsWlanApi
    193 WindowsWlanApi::WindowsWlanApi(HINSTANCE library)
    194     : library_(library) {
    195   GetWLANFunctions(library_);
    196 }
    197 
    198 WindowsWlanApi::~WindowsWlanApi() {
    199   FreeLibrary(library_);
    200 }
    201 
    202 WindowsWlanApi* WindowsWlanApi::Create() {
    203   if (base::win::GetVersion() < base::win::VERSION_VISTA)
    204     return NULL;
    205   // We use an absolute path to load the DLL to avoid DLL preloading attacks.
    206   string16 system_directory;
    207   if (!GetSystemDirectory(&system_directory)) {
    208     return NULL;
    209   }
    210   DCHECK(!system_directory.empty());
    211   string16 dll_path = system_directory + L"wlanapi.dll";
    212   HINSTANCE library = LoadLibraryEx(dll_path.c_str(),
    213                                     NULL,
    214                                     LOAD_WITH_ALTERED_SEARCH_PATH);
    215   if (!library) {
    216     return NULL;
    217   }
    218   return new WindowsWlanApi(library);
    219 }
    220 
    221 void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) {
    222   DCHECK(wlan_library);
    223   WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>(
    224       GetProcAddress(wlan_library, "WlanOpenHandle"));
    225   WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>(
    226       GetProcAddress(wlan_library, "WlanEnumInterfaces"));
    227   WlanGetNetworkBssList_function_ =
    228       reinterpret_cast<WlanGetNetworkBssListFunction>(
    229       GetProcAddress(wlan_library, "WlanGetNetworkBssList"));
    230   WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>(
    231       GetProcAddress(wlan_library, "WlanFreeMemory"));
    232   WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>(
    233       GetProcAddress(wlan_library, "WlanCloseHandle"));
    234   DCHECK(WlanOpenHandle_function_ &&
    235          WlanEnumInterfaces_function_ &&
    236          WlanGetNetworkBssList_function_ &&
    237          WlanFreeMemory_function_ &&
    238          WlanCloseHandle_function_);
    239 }
    240 
    241 void WindowsWlanApi::LogWlanInterfaceCount(int count) {
    242   UMA_HISTOGRAM_CUSTOM_COUNTS(
    243       "Net.Wifi.InterfaceCount",
    244       count,
    245       1,
    246       5,
    247       5);
    248 }
    249 
    250 bool WindowsWlanApi::GetAccessPointData(
    251     WifiData::AccessPointDataSet* data) {
    252   DCHECK(data);
    253 
    254   // Get the handle to the WLAN API.
    255   DWORD negotiated_version;
    256   HANDLE wlan_handle = NULL;
    257   // We could be executing on either Windows XP or Windows Vista, so use the
    258   // lower version of the client WLAN API. It seems that the negotiated version
    259   // is the Vista version irrespective of what we pass!
    260   static const int kXpWlanClientVersion = 1;
    261   if ((*WlanOpenHandle_function_)(kXpWlanClientVersion,
    262                                   NULL,
    263                                   &negotiated_version,
    264                                   &wlan_handle) != ERROR_SUCCESS) {
    265     LogWlanInterfaceCount(0);
    266     return false;
    267   }
    268   DCHECK(wlan_handle);
    269 
    270   // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
    271   WLAN_INTERFACE_INFO_LIST* interface_list = NULL;
    272   if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) !=
    273       ERROR_SUCCESS) {
    274     LogWlanInterfaceCount(0);
    275     return false;
    276   }
    277   DCHECK(interface_list);
    278 
    279   LogWlanInterfaceCount(interface_list->dwNumberOfItems);
    280 
    281   // Go through the list of interfaces and get the data for each.
    282   for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) {
    283     // Skip any interface that is midway through association; the
    284     // WlanGetNetworkBssList function call is known to hang indefinitely
    285     // when it's in this state. http://crbug.com/39300
    286     if (interface_list->InterfaceInfo[i].isState ==
    287         wlan_interface_state_associating) {
    288       LOG(WARNING) << "Skipping wifi scan on adapter " << i << " ("
    289                    << interface_list->InterfaceInfo[i].strInterfaceDescription
    290                    << ") in 'associating' state. Repeated occurrences "
    291                       "indicates a non-responding adapter.";
    292       continue;
    293     }
    294     GetInterfaceDataWLAN(wlan_handle,
    295                          interface_list->InterfaceInfo[i].InterfaceGuid,
    296                          data);
    297   }
    298 
    299   // Free interface_list.
    300   (*WlanFreeMemory_function_)(interface_list);
    301 
    302   // Close the handle.
    303   if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) {
    304     return false;
    305   }
    306 
    307   return true;
    308 }
    309 
    310 // Appends the data for a single interface to the data vector. Returns the
    311 // number of access points found, or -1 on error.
    312 int WindowsWlanApi::GetInterfaceDataWLAN(
    313     const HANDLE wlan_handle,
    314     const GUID& interface_id,
    315     WifiData::AccessPointDataSet* data) {
    316   DCHECK(data);
    317 
    318   const base::TimeTicks start_time = base::TimeTicks::Now();
    319 
    320   // WlanGetNetworkBssList allocates bss_list.
    321   WLAN_BSS_LIST* bss_list = NULL;
    322   if ((*WlanGetNetworkBssList_function_)(wlan_handle,
    323                                          &interface_id,
    324                                          NULL,   // Use all SSIDs.
    325                                          dot11_BSS_type_any,
    326                                          false,  // bSecurityEnabled - unused
    327                                          NULL,   // reserved
    328                                          &bss_list) != ERROR_SUCCESS) {
    329     return -1;
    330   }
    331   // According to http://www.attnetclient.com/kb/questions.php?questionid=75
    332   // WlanGetNetworkBssList can sometimes return success, but leave the bss
    333   // list as NULL.
    334   if (!bss_list)
    335     return -1;
    336 
    337   const base::TimeDelta duration = base::TimeTicks::Now() - start_time;
    338 
    339   UMA_HISTOGRAM_CUSTOM_TIMES(
    340       "Net.Wifi.ScanLatency",
    341       duration,
    342       base::TimeDelta::FromMilliseconds(1),
    343       base::TimeDelta::FromMinutes(1),
    344       100);
    345 
    346 
    347   int found = 0;
    348   for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) {
    349     AccessPointData access_point_data;
    350     if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) {
    351       ++found;
    352       data->insert(access_point_data);
    353     }
    354   }
    355 
    356   (*WlanFreeMemory_function_)(bss_list);
    357 
    358   return found;
    359 }
    360 
    361 // WindowsNdisApi
    362 WindowsNdisApi::WindowsNdisApi(
    363     std::vector<string16>* interface_service_names)
    364     : oid_buffer_size_(kInitialBufferSize) {
    365   DCHECK(!interface_service_names->empty());
    366   interface_service_names_.swap(*interface_service_names);
    367 }
    368 
    369 WindowsNdisApi::~WindowsNdisApi() {
    370 }
    371 
    372 WindowsNdisApi* WindowsNdisApi::Create() {
    373   std::vector<string16> interface_service_names;
    374   if (GetInterfacesNDIS(&interface_service_names)) {
    375     return new WindowsNdisApi(&interface_service_names);
    376   }
    377   return NULL;
    378 }
    379 
    380 bool WindowsNdisApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
    381   DCHECK(data);
    382   int interfaces_failed = 0;
    383   int interfaces_succeeded = 0;
    384 
    385   for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) {
    386     // First, check that we have a DOS device for this adapter.
    387     if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) {
    388       continue;
    389     }
    390 
    391     // Get the handle to the device. This will fail if the named device is not
    392     // valid.
    393     HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]);
    394     if (adapter_handle == INVALID_HANDLE_VALUE) {
    395       continue;
    396     }
    397 
    398     // Get the data.
    399     if (GetInterfaceDataNDIS(adapter_handle, data)) {
    400       ++interfaces_succeeded;
    401     } else {
    402       ++interfaces_failed;
    403     }
    404 
    405     // Clean up.
    406     CloseHandle(adapter_handle);
    407     UndefineDosDevice(interface_service_names_[i]);
    408   }
    409 
    410   // Return true if at least one interface succeeded, or at the very least none
    411   // failed.
    412   return interfaces_succeeded > 0 || interfaces_failed == 0;
    413 }
    414 
    415 bool WindowsNdisApi::GetInterfacesNDIS(
    416     std::vector<string16>* interface_service_names_out) {
    417   HKEY network_cards_key = NULL;
    418   if (RegOpenKeyEx(
    419       HKEY_LOCAL_MACHINE,
    420       L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
    421       0,
    422       KEY_READ,
    423       &network_cards_key) != ERROR_SUCCESS) {
    424     return false;
    425   }
    426   DCHECK(network_cards_key);
    427 
    428   for (int i = 0; ; ++i) {
    429     TCHAR name[kStringLength];
    430     DWORD name_size = kStringLength;
    431     FILETIME time;
    432     if (RegEnumKeyEx(network_cards_key,
    433                      i,
    434                      name,
    435                      &name_size,
    436                      NULL,
    437                      NULL,
    438                      NULL,
    439                      &time) != ERROR_SUCCESS) {
    440       break;
    441     }
    442     HKEY hardware_key = NULL;
    443     if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) !=
    444         ERROR_SUCCESS) {
    445       break;
    446     }
    447     DCHECK(hardware_key);
    448 
    449     TCHAR service_name[kStringLength];
    450     DWORD service_name_size = kStringLength;
    451     DWORD type = 0;
    452     if (RegQueryValueEx(hardware_key,
    453                         L"ServiceName",
    454                         NULL,
    455                         &type,
    456                         reinterpret_cast<LPBYTE>(service_name),
    457                         &service_name_size) == ERROR_SUCCESS) {
    458       interface_service_names_out->push_back(service_name);
    459     }
    460     RegCloseKey(hardware_key);
    461   }
    462 
    463   RegCloseKey(network_cards_key);
    464   return true;
    465 }
    466 
    467 
    468 bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle,
    469                                           WifiData::AccessPointDataSet* data) {
    470   DCHECK(data);
    471 
    472   scoped_ptr_malloc<BYTE> buffer(
    473       reinterpret_cast<BYTE*>(malloc(oid_buffer_size_)));
    474   if (buffer == NULL) {
    475     return false;
    476   }
    477 
    478   DWORD bytes_out;
    479   int result;
    480 
    481   while (true) {
    482     bytes_out = 0;
    483     result = PerformQuery(adapter_handle, buffer.get(),
    484                           oid_buffer_size_, &bytes_out);
    485     if (result == ERROR_GEN_FAILURE ||  // Returned by some Intel cards.
    486         result == ERROR_INSUFFICIENT_BUFFER ||
    487         result == ERROR_MORE_DATA ||
    488         result == NDIS_STATUS_INVALID_LENGTH ||
    489         result == NDIS_STATUS_BUFFER_TOO_SHORT) {
    490       // The buffer we supplied is too small, so increase it. bytes_out should
    491       // provide the required buffer size, but this is not always the case.
    492       if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) {
    493         oid_buffer_size_ = bytes_out;
    494       } else {
    495         oid_buffer_size_ *= 2;
    496       }
    497       if (!ResizeBuffer(oid_buffer_size_, &buffer)) {
    498         oid_buffer_size_ = kInitialBufferSize;  // Reset for next time.
    499         return false;
    500       }
    501     } else {
    502       // The buffer is not too small.
    503       break;
    504     }
    505   }
    506   DCHECK(buffer.get());
    507 
    508   if (result == ERROR_SUCCESS) {
    509     NDIS_802_11_BSSID_LIST* bssid_list =
    510         reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer.get());
    511     GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data);
    512   }
    513 
    514   return true;
    515 }
    516 
    517 bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
    518                     AccessPointData* access_point_data) {
    519   // Currently we get only MAC address, signal strength and SSID.
    520   DCHECK(access_point_data);
    521   access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid);
    522   access_point_data->radio_signal_strength = bss_entry.lRssi;
    523   // bss_entry.dot11Ssid.ucSSID is not null-terminated.
    524   UTF8ToUTF16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID),
    525               static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength),
    526               &access_point_data->ssid);
    527   // TODO(steveblock): Is it possible to get the following?
    528   // access_point_data->signal_to_noise
    529   // access_point_data->age
    530   // access_point_data->channel
    531   return true;
    532 }
    533 
    534 bool UndefineDosDevice(const string16& device_name) {
    535   // We remove only the mapping we use, that is \Device\<device_name>.
    536   string16 target_path = L"\\Device\\" + device_name;
    537   return DefineDosDevice(
    538       DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
    539       device_name.c_str(),
    540       target_path.c_str()) == TRUE;
    541 }
    542 
    543 bool DefineDosDeviceIfNotExists(const string16& device_name) {
    544   // We create a DOS device name for the device at \Device\<device_name>.
    545   string16 target_path = L"\\Device\\" + device_name;
    546 
    547   TCHAR target[kStringLength];
    548   if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
    549       target_path.compare(target) == 0) {
    550     // Device already exists.
    551     return true;
    552   }
    553 
    554   if (GetLastError() != ERROR_FILE_NOT_FOUND) {
    555     return false;
    556   }
    557 
    558   if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
    559                        device_name.c_str(),
    560                        target_path.c_str())) {
    561     return false;
    562   }
    563 
    564   // Check that the device is really there.
    565   return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
    566       target_path.compare(target) == 0;
    567 }
    568 
    569 HANDLE GetFileHandle(const string16& device_name) {
    570   // We access a device with DOS path \Device\<device_name> at
    571   // \\.\<device_name>.
    572   string16 formatted_device_name = L"\\\\.\\" + device_name;
    573 
    574   return CreateFile(formatted_device_name.c_str(),
    575                     GENERIC_READ,
    576                     FILE_SHARE_READ | FILE_SHARE_WRITE,  // share mode
    577                     0,  // security attributes
    578                     OPEN_EXISTING,
    579                     0,  // flags and attributes
    580                     INVALID_HANDLE_VALUE);
    581 }
    582 
    583 int PerformQuery(HANDLE adapter_handle,
    584                  BYTE* buffer,
    585                  DWORD buffer_size,
    586                  DWORD* bytes_out) {
    587   DWORD oid = OID_802_11_BSSID_LIST;
    588   if (!DeviceIoControl(adapter_handle,
    589                        IOCTL_NDIS_QUERY_GLOBAL_STATS,
    590                        &oid,
    591                        sizeof(oid),
    592                        buffer,
    593                        buffer_size,
    594                        bytes_out,
    595                        NULL)) {
    596     return GetLastError();
    597   }
    598   return ERROR_SUCCESS;
    599 }
    600 
    601 bool ResizeBuffer(int requested_size, scoped_ptr_malloc<BYTE>* buffer) {
    602   DCHECK_GT(requested_size, 0);
    603   DCHECK(buffer);
    604   if (requested_size > kMaximumBufferSize) {
    605     buffer->reset();
    606     return false;
    607   }
    608 
    609   buffer->reset(reinterpret_cast<BYTE*>(
    610       realloc(buffer->release(), requested_size)));
    611   return buffer != NULL;
    612 }
    613 
    614 bool GetSystemDirectory(string16* path) {
    615   DCHECK(path);
    616   // Return value includes terminating NULL.
    617   int buffer_size = ::GetSystemDirectory(NULL, 0);
    618   if (buffer_size == 0) {
    619     return false;
    620   }
    621   scoped_ptr<char16[]> buffer(new char16[buffer_size]);
    622 
    623   // Return value excludes terminating NULL.
    624   int characters_written = ::GetSystemDirectory(buffer.get(), buffer_size);
    625   if (characters_written == 0) {
    626     return false;
    627   }
    628   DCHECK_EQ(buffer_size - 1, characters_written);
    629 
    630   path->assign(buffer.get(), characters_written);
    631 
    632   if (*path->rbegin() != L'\\') {
    633     path->append(L"\\");
    634   }
    635   DCHECK_EQ(L'\\', *path->rbegin());
    636   return true;
    637 }
    638 }  // namespace
    639 
    640 }  // namespace content
    641