15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2010 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// also support a limited version of the WLAN API. See
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// wlanapi.h, which is not part of the SDK used by Gears, so is replicated
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// locally using data from the MSDN.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows XP from Service Pack 2 onwards supports the Wireless Zero
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Configuration (WZC) programming interface. See
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The MSDN recommends that one use the WLAN API where available, and WZC
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// otherwise.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// However, it seems that WZC fails for some wireless cards. Also, WLAN seems
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// otherwise.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/geolocation/wifi_data_provider_win.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <winioctl.h>
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wlanapi.h>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/geolocation/wifi_data_provider_common.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/geolocation/wifi_data_provider_common_win.h"
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "content/browser/geolocation/wifi_data_provider_manager.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Taken from ndis.h for WinCE.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NDIS_STATUS_INVALID_LENGTH   ((NDIS_STATUS)0xC0010014L)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The limits on the size of the buffer used for the OID query.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInitialBufferSize = 2 << 12;  // Good for about 50 APs.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaximumBufferSize = 2 << 20;  // 2MB
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Length for generic string buffers passed to Windows APIs.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStringLength = 512;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The time periods, in milliseconds, between successive polls of the wifi data.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDefaultPollingInterval = 10000;  // 10s
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNoChangePollingInterval = 120000;  // 2 mins
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTwoNoChangePollingInterval = 600000;  // 10 mins
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WlanOpenHandle
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef DWORD (WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               PVOID pReserved,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               PDWORD pdwNegotiatedVersion,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               PHANDLE phClientHandle);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WlanEnumInterfaces
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef DWORD (WINAPI* WlanEnumInterfacesFunction)(
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE hClientHandle,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PVOID pReserved,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PWLAN_INTERFACE_INFO_LIST* ppInterfaceList);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WlanGetNetworkBssList
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)(
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE hClientHandle,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GUID* pInterfaceGuid,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const  PDOT11_SSID pDot11Ssid,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DOT11_BSS_TYPE dot11BssType,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BOOL bSecurityEnabled,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PVOID pReserved,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PWLAN_BSS_LIST* ppWlanBssList
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WlanFreeMemory
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef VOID (WINAPI* WlanFreeMemoryFunction)(PVOID pMemory);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WlanCloseHandle
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef DWORD (WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                PVOID pReserved);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Local classes and functions
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WindowsWlanApi : public WifiDataProviderCommon::WlanApiInterface {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~WindowsWlanApi();
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Factory function. Will return NULL if this API is unavailable.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static WindowsWlanApi* Create();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WlanApiInterface
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Takes ownership of the library handle.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit WindowsWlanApi(HINSTANCE library);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Loads the required functions from the DLL.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void GetWLANFunctions(HINSTANCE wlan_library);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int GetInterfaceDataWLAN(HANDLE wlan_handle,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const GUID& interface_id,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           WifiData::AccessPointDataSet* data);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Logs number of detected wlan interfaces.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void LogWlanInterfaceCount(int count);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle to the wlanapi.dll library.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HINSTANCE library_;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Function pointers for WLAN
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanOpenHandleFunction WlanOpenHandle_function_;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanFreeMemoryFunction WlanFreeMemory_function_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanCloseHandleFunction WlanCloseHandle_function_;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WindowsNdisApi : public WifiDataProviderCommon::WlanApiInterface {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~WindowsNdisApi();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static WindowsNdisApi* Create();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WlanApiInterface
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool GetInterfacesNDIS(
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      std::vector<base::string16>* interface_service_names_out);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Swaps in content of the vector passed
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  explicit WindowsNdisApi(std::vector<base::string16>* interface_service_names);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetInterfaceDataNDIS(HANDLE adapter_handle,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            WifiData::AccessPointDataSet* data);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NDIS variables.
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<base::string16> interface_service_names_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remembers scan result buffer size across calls.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int oid_buffer_size_;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Extracts data for an access point and converts to Gears format.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    AccessPointData* access_point_data);
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool UndefineDosDevice(const base::string16& device_name);
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool DefineDosDeviceIfNotExists(const base::string16& device_name);
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HANDLE GetFileHandle(const base::string16& device_name);
15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Makes the OID query and returns a Windows API error code.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PerformQuery(HANDLE adapter_handle,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 BYTE* buffer,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 DWORD buffer_size,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 DWORD* bytes_out);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ResizeBuffer(int requested_size,
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  scoped_ptr<BYTE, base::FreeDeleter>* buffer);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the system directory and appends a trailing slash if not already
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// present.
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool GetSystemDirectory(base::string16* path);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return new WifiDataProviderWin();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)WifiDataProviderWin::WifiDataProviderWin() {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)WifiDataProviderWin::~WifiDataProviderWin() {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)WifiDataProviderCommon::WlanApiInterface* WifiDataProviderWin::NewWlanApi() {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use the WLAN interface if we're on Vista and if it's available. Otherwise,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use NDIS.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanApiInterface* api = WindowsWlanApi::Create();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (api) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return api;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WindowsNdisApi::Create();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)WifiPollingPolicy* WifiDataProviderWin::NewPollingPolicy() {
18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return new GenericWifiPollingPolicy<kDefaultPollingInterval,
18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                      kNoChangePollingInterval,
18658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                      kTwoNoChangePollingInterval,
18758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                      kNoWifiPollingIntervalMilliseconds>;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Local classes and functions
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WindowsWlanApi
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowsWlanApi::WindowsWlanApi(HINSTANCE library)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : library_(library) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetWLANFunctions(library_);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowsWlanApi::~WindowsWlanApi() {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreeLibrary(library_);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowsWlanApi* WindowsWlanApi::Create() {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_VISTA)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We use an absolute path to load the DLL to avoid DLL preloading attacks.
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 system_directory;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetSystemDirectory(&system_directory)) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!system_directory.empty());
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 dll_path = system_directory + L"wlanapi.dll";
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HINSTANCE library = LoadLibraryEx(dll_path.c_str(),
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    NULL,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    LOAD_WITH_ALTERED_SEARCH_PATH);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!library) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new WindowsWlanApi(library);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(wlan_library);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>(
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(wlan_library, "WlanOpenHandle"));
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>(
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(wlan_library, "WlanEnumInterfaces"));
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanGetNetworkBssList_function_ =
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<WlanGetNetworkBssListFunction>(
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(wlan_library, "WlanGetNetworkBssList"));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>(
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(wlan_library, "WlanFreeMemory"));
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>(
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetProcAddress(wlan_library, "WlanCloseHandle"));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(WlanOpenHandle_function_ &&
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         WlanEnumInterfaces_function_ &&
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         WlanGetNetworkBssList_function_ &&
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         WlanFreeMemory_function_ &&
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         WlanCloseHandle_function_);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WindowsWlanApi::LogWlanInterfaceCount(int count) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS(
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Net.Wifi.InterfaceCount",
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      count,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      5,
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      6);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WindowsWlanApi::GetAccessPointData(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WifiData::AccessPointDataSet* data) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the handle to the WLAN API.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD negotiated_version;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE wlan_handle = NULL;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We could be executing on either Windows XP or Windows Vista, so use the
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lower version of the client WLAN API. It seems that the negotiated version
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is the Vista version irrespective of what we pass!
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kXpWlanClientVersion = 1;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((*WlanOpenHandle_function_)(kXpWlanClientVersion,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  NULL,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  &negotiated_version,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  &wlan_handle) != ERROR_SUCCESS) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LogWlanInterfaceCount(0);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(wlan_handle);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WLAN_INTERFACE_INFO_LIST* interface_list = NULL;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) !=
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ERROR_SUCCESS) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LogWlanInterfaceCount(0);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(interface_list);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LogWlanInterfaceCount(interface_list->dwNumberOfItems);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Go through the list of interfaces and get the data for each.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip any interface that is midway through association; the
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // WlanGetNetworkBssList function call is known to hang indefinitely
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // when it's in this state. http://crbug.com/39300
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (interface_list->InterfaceInfo[i].isState ==
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wlan_interface_state_associating) {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Skipping wifi scan on adapter " << i << " ("
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << interface_list->InterfaceInfo[i].strInterfaceDescription
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << ") in 'associating' state. Repeated occurrences "
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "indicates a non-responding adapter.";
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetInterfaceDataWLAN(wlan_handle,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         interface_list->InterfaceInfo[i].InterfaceGuid,
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         data);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Free interface_list.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*WlanFreeMemory_function_)(interface_list);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close the handle.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Appends the data for a single interface to the data vector. Returns the
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// number of access points found, or -1 on error.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WindowsWlanApi::GetInterfaceDataWLAN(
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const HANDLE wlan_handle,
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GUID& interface_id,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WifiData::AccessPointDataSet* data) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeTicks start_time = base::TimeTicks::Now();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WlanGetNetworkBssList allocates bss_list.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WLAN_BSS_LIST* bss_list = NULL;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((*WlanGetNetworkBssList_function_)(wlan_handle,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &interface_id,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         NULL,   // Use all SSIDs.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         dot11_BSS_type_any,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         false,  // bSecurityEnabled - unused
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         NULL,   // reserved
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &bss_list) != ERROR_SUCCESS) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // According to http://www.attnetclient.com/kb/questions.php?questionid=75
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WlanGetNetworkBssList can sometimes return success, but leave the bss
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // list as NULL.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bss_list)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeDelta duration = base::TimeTicks::Now() - start_time;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_TIMES(
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Net.Wifi.ScanLatency",
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      duration,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(1),
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMinutes(1),
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      100);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int found = 0;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AccessPointData access_point_data;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++found;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data->insert(access_point_data);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*WlanFreeMemory_function_)(bss_list);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return found;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WindowsNdisApi
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowsNdisApi::WindowsNdisApi(
364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    std::vector<base::string16>* interface_service_names)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : oid_buffer_size_(kInitialBufferSize) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!interface_service_names->empty());
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  interface_service_names_.swap(*interface_service_names);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowsNdisApi::~WindowsNdisApi() {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WindowsNdisApi* WindowsNdisApi::Create() {
374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<base::string16> interface_service_names;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetInterfacesNDIS(&interface_service_names)) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return new WindowsNdisApi(&interface_service_names);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WindowsNdisApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int interfaces_failed = 0;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int interfaces_succeeded = 0;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // First, check that we have a DOS device for this adapter.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the handle to the device. This will fail if the named device is not
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // valid.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (adapter_handle == INVALID_HANDLE_VALUE) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the data.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetInterfaceDataNDIS(adapter_handle, data)) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++interfaces_succeeded;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++interfaces_failed;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Clean up.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseHandle(adapter_handle);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UndefineDosDevice(interface_service_names_[i]);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return true if at least one interface succeeded, or at the very least none
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // failed.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return interfaces_succeeded > 0 || interfaces_failed == 0;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WindowsNdisApi::GetInterfacesNDIS(
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    std::vector<base::string16>* interface_service_names_out) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HKEY network_cards_key = NULL;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (RegOpenKeyEx(
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HKEY_LOCAL_MACHINE,
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0,
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      KEY_READ,
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &network_cards_key) != ERROR_SUCCESS) {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(network_cards_key);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; ; ++i) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TCHAR name[kStringLength];
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD name_size = kStringLength;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILETIME time;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (RegEnumKeyEx(network_cards_key,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     i,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     name,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     &name_size,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     NULL,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     NULL,
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     NULL,
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     &time) != ERROR_SUCCESS) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HKEY hardware_key = NULL;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) !=
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ERROR_SUCCESS) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(hardware_key);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TCHAR service_name[kStringLength];
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD service_name_size = kStringLength;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD type = 0;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (RegQueryValueEx(hardware_key,
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        L"ServiceName",
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        NULL,
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &type,
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        reinterpret_cast<LPBYTE>(service_name),
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &service_name_size) == ERROR_SUCCESS) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      interface_service_names_out->push_back(service_name);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegCloseKey(hardware_key);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegCloseKey(network_cards_key);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle,
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          WifiData::AccessPointDataSet* data) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(data);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<BYTE, base::FreeDeleter> buffer(
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<BYTE*>(malloc(oid_buffer_size_)));
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (buffer == NULL) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD bytes_out;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bytes_out = 0;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = PerformQuery(adapter_handle, buffer.get(),
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          oid_buffer_size_, &bytes_out);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result == ERROR_GEN_FAILURE ||  // Returned by some Intel cards.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result == ERROR_INSUFFICIENT_BUFFER ||
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result == ERROR_MORE_DATA ||
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result == NDIS_STATUS_INVALID_LENGTH ||
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result == NDIS_STATUS_BUFFER_TOO_SHORT) {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The buffer we supplied is too small, so increase it. bytes_out should
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // provide the required buffer size, but this is not always the case.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        oid_buffer_size_ = bytes_out;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        oid_buffer_size_ *= 2;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!ResizeBuffer(oid_buffer_size_, &buffer)) {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        oid_buffer_size_ = kInitialBufferSize;  // Reset for next time.
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The buffer is not too small.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffer.get());
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == ERROR_SUCCESS) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NDIS_802_11_BSSID_LIST* bssid_list =
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer.get());
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    AccessPointData* access_point_data) {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Currently we get only MAC address, signal strength and SSID.
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(access_point_data);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  access_point_data->radio_signal_strength = bss_entry.lRssi;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bss_entry.dot11Ssid.ucSSID is not null-terminated.
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::UTF8ToUTF16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID),
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength),
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    &access_point_data->ssid);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(steveblock): Is it possible to get the following?
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // access_point_data->signal_to_noise
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // access_point_data->age
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // access_point_data->channel
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool UndefineDosDevice(const base::string16& device_name) {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We remove only the mapping we use, that is \Device\<device_name>.
537a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 target_path = L"\\Device\\" + device_name;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DefineDosDevice(
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_name.c_str(),
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      target_path.c_str()) == TRUE;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
544a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool DefineDosDeviceIfNotExists(const base::string16& device_name) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We create a DOS device name for the device at \Device\<device_name>.
546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 target_path = L"\\Device\\" + device_name;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TCHAR target[kStringLength];
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      target_path.compare(target) == 0) {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Device already exists.
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetLastError() != ERROR_FILE_NOT_FOUND) {
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       device_name.c_str(),
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       target_path.c_str())) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that the device is really there.
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      target_path.compare(target) == 0;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
570a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HANDLE GetFileHandle(const base::string16& device_name) {
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We access a device with DOS path \Device\<device_name> at
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // \\.\<device_name>.
573a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 formatted_device_name = L"\\\\.\\" + device_name;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateFile(formatted_device_name.c_str(),
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    GENERIC_READ,
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FILE_SHARE_READ | FILE_SHARE_WRITE,  // share mode
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    0,  // security attributes
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OPEN_EXISTING,
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    0,  // flags and attributes
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    INVALID_HANDLE_VALUE);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PerformQuery(HANDLE adapter_handle,
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 BYTE* buffer,
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 DWORD buffer_size,
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 DWORD* bytes_out) {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD oid = OID_802_11_BSSID_LIST;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!DeviceIoControl(adapter_handle,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       IOCTL_NDIS_QUERY_GLOBAL_STATS,
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &oid,
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       sizeof(oid),
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       buffer,
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       buffer_size,
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       bytes_out,
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       NULL)) {
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetLastError();
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ERROR_SUCCESS;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ResizeBuffer(int requested_size,
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  scoped_ptr<BYTE, base::FreeDeleter>* buffer) {
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(requested_size, 0);
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffer);
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (requested_size > kMaximumBufferSize) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->reset();
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer->reset(reinterpret_cast<BYTE*>(
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      realloc(buffer->release(), requested_size)));
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return buffer != NULL;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
616a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool GetSystemDirectory(base::string16* path) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(path);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return value includes terminating NULL.
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int buffer_size = ::GetSystemDirectory(NULL, 0);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (buffer_size == 0) {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::char16[]> buffer(new base::char16[buffer_size]);
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return value excludes terminating NULL.
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int characters_written = ::GetSystemDirectory(buffer.get(), buffer_size);
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (characters_written == 0) {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(buffer_size - 1, characters_written);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path->assign(buffer.get(), characters_written);
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*path->rbegin() != L'\\') {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path->append(L"\\");
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(L'\\', *path->rbegin());
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
643