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