From 0f11a5757984965c2baa189b47d5a0cef49a707e Mon Sep 17 00:00:00 2001
From: "joth@chromium.org"
 <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Mon, 25 Jan 2010 16:47:24 +0000
Subject: Adding geolocation data provider infrastructure to Chrome. These
 files are lifted from gears:
 http://code.google.com/p/gears/source/browse/trunk/gears/geolocation/

NOTE this is a direct copy of gears files; subsequent edits will be made to bring them into chrome style and add to gypi files and so on.

BUG=11246
TEST=None (just adding placeholder files; tests will follow in next change)

Review URL: http://codereview.chromium.org/546116

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37009 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/browser/geolocation/device_data_provider.h  | 391 +++++++++++++++
 .../geolocation/empty_device_data_provider.cc      |  39 ++
 .../geolocation/empty_device_data_provider.h       |  51 ++
 .../geolocation/wifi_data_provider_common.cc       |  95 ++++
 .../geolocation/wifi_data_provider_common.h        |  39 ++
 .../geolocation/wifi_data_provider_linux.cc        | 279 +++++++++++
 .../browser/geolocation/wifi_data_provider_linux.h |  59 +++
 .../browser/geolocation/wifi_data_provider_osx.cc  | 168 +++++++
 .../browser/geolocation/wifi_data_provider_osx.h   |  71 +++
 .../browser/geolocation/wifi_data_provider_win.cc  | 534 +++++++++++++++++++++
 .../browser/geolocation/wifi_data_provider_win.h   |  87 ++++
 .../wifi_data_provider_windows_common.cc           |  76 +++
 .../wifi_data_provider_windows_common.h            |  45 ++
 13 files changed, 1934 insertions(+)
 create mode 100644 chrome/browser/geolocation/device_data_provider.h
 create mode 100644 chrome/browser/geolocation/empty_device_data_provider.cc
 create mode 100644 chrome/browser/geolocation/empty_device_data_provider.h
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_common.cc
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_common.h
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_linux.cc
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_linux.h
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_osx.cc
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_osx.h
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_win.cc
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_win.h
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_windows_common.cc
 create mode 100644 chrome/browser/geolocation/wifi_data_provider_windows_common.h

(limited to 'chrome/browser')

diff --git a/chrome/browser/geolocation/device_data_provider.h b/chrome/browser/geolocation/device_data_provider.h
new file mode 100644
index 0000000..6d5740e
--- /dev/null
+++ b/chrome/browser/geolocation/device_data_provider.h
@@ -0,0 +1,391 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// A device data provider provides data from the device that is used by a
+// NetworkLocationProvider to obtain a position fix. This data may be either
+// cell radio data or wifi data. For a given type of data, we use a singleton
+// instance of the device data provider, which is used by multiple
+// NetworkLocationProvider objects.
+//
+// This file providers DeviceDataProvider, which provides static methods to
+// access the singleton instance. The singleton instance uses a private
+// implementation to abstract across platforms and also to allow mock providers
+// to be used for testing.
+//
+// This file also provides DeviceDataProviderImplBase, a base class which
+// provides commom functionality for the private implementations.
+//
+// This file also declares the data structures used to represent cell radio data
+// and wifi data.
+
+#ifndef GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__
+#define GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__
+
+#include <algorithm>
+#include <set>
+#include <vector>
+#include "gears/base/common/basictypes.h"  // For int64
+#include "gears/base/common/common.h"
+#include "gears/base/common/mutex.h"
+#include "gears/base/common/scoped_refptr.h"  // For RefCount
+#include "gears/base/common/string16.h"
+#include "third_party/scoped_ptr/scoped_ptr.h"
+
+// The following data structures are used to store cell radio data and wifi
+// data. See the Geolocation API design document at
+// http://code.google.com/p/google-gears/wiki/LocationAPI for a more complete
+// description.
+//
+// For all integer fields, we use kint32min to represent unknown values.
+
+// Cell radio data relating to a single cell tower.
+struct CellData {
+  CellData()
+      : cell_id(kint32min),
+        location_area_code(kint32min),
+        mobile_network_code(kint32min),
+        mobile_country_code(kint32min),
+        age(kint32min),
+        radio_signal_strength(kint32min),
+        timing_advance(kint32min) {}
+  bool Matches(const CellData &other) const {
+    // Ignore age and radio_signal_strength when matching.
+    return cell_id == other.cell_id &&
+           location_area_code == other.location_area_code &&
+           mobile_network_code == other.mobile_network_code &&
+           mobile_country_code == other.mobile_country_code &&
+           timing_advance == other.timing_advance;
+  }
+
+  int cell_id;                // Unique identifier of the cell
+  int location_area_code;     // For current location area
+  int mobile_network_code;    // For current cell
+  int mobile_country_code;    // For current cell
+  int age;                    // Milliseconds since this cell was primary
+  int radio_signal_strength;  // Measured in dBm.
+  int timing_advance;         // Timing advance representing the distance from
+                              // the cell tower. Each unit is roughly 550
+                              // meters.
+};
+
+static bool CellDataMatches(const CellData &data1, const CellData &data2) {
+  return data1.Matches(data2);
+}
+
+enum RadioType {
+  RADIO_TYPE_UNKNOWN,
+  RADIO_TYPE_GSM,
+  RADIO_TYPE_CDMA,
+  RADIO_TYPE_WCDMA,
+};
+
+// All data for the cell radio.
+struct RadioData {
+  RadioData()
+      : home_mobile_network_code(kint32min),
+        home_mobile_country_code(kint32min),
+        radio_type(RADIO_TYPE_UNKNOWN) {}
+  bool Matches(const RadioData &other) const {
+    if (cell_data.size() != other.cell_data.size()) {
+      return false;
+    }
+    if (!std::equal(cell_data.begin(), cell_data.end(), other.cell_data.begin(),
+                    CellDataMatches)) {
+      return false;
+    }
+    return device_id == other.device_id &&
+           home_mobile_network_code == other.home_mobile_network_code &&
+           home_mobile_country_code == other.home_mobile_country_code &&
+           radio_type == other.radio_type &&
+           carrier == other.carrier;
+  }
+  // Determines whether a new set of radio data differs significantly from this.
+  bool DiffersSignificantly(const RadioData &other) const {
+    // This is required by MockDeviceDataProviderImpl.
+    // TODO(steveblock): Implement properly.
+    return !Matches(other);
+  }
+
+  std::string16 device_id;
+  std::vector<CellData> cell_data;
+  int home_mobile_network_code;  // For the device's home network.
+  int home_mobile_country_code;  // For the device's home network.
+  RadioType radio_type;          // Mobile radio type.
+  std::string16 carrier;         // Carrier name.
+};
+
+// Wifi data relating to a single access point.
+struct AccessPointData {
+  AccessPointData()
+      : radio_signal_strength(kint32min),
+        age(kint32min),
+        channel(kint32min),
+        signal_to_noise(kint32min) {}
+
+  std::string16 mac_address;
+  int radio_signal_strength;  // Measured in dBm
+  int age;              // Milliseconds since this access point was detected
+  int channel;
+  int signal_to_noise;  // Ratio in dB
+  std::string16 ssid;   // Network identifier
+};
+
+// This is to allow AccessPointData to be used in std::set. We order
+// lexicographically by MAC address.
+struct AccessPointDataLess : public std::less<AccessPointData> {
+  bool operator()(const AccessPointData &data1,
+                  const AccessPointData &data2) const {
+    return data1.mac_address < data2.mac_address;
+  }
+};
+
+// All data for wifi.
+struct WifiData {
+  // Determines whether a new set of WiFi data differs significantly from this.
+  bool DiffersSignificantly(const WifiData &other) const {
+    // At least 5 or 50% of access points added or removed is significant.
+    static const size_t kMinChangedAccessPoints = 5;
+
+    // Compute size of interesction of old and new sets.
+    size_t num_common = 0;
+    for (AccessPointDataSet::const_iterator iter = access_point_data.begin();
+         iter != access_point_data.end();
+         iter++) {
+      if (other.access_point_data.find(*iter) !=
+          other.access_point_data.end()) {
+        ++num_common;
+      }
+    }
+    assert(num_common <= access_point_data.size());
+    assert(num_common <= other.access_point_data.size());
+
+    // Test how many have changed.
+    size_t added_or_removed = std::max(
+        other.access_point_data.size() - num_common,
+        access_point_data.size() - num_common);
+    return added_or_removed >=
+        std::min(kMinChangedAccessPoints, access_point_data.size() / 2);
+  }
+
+  // Store access points as a set, sorted by MAC address. This allows quick
+  // comparison of sets for detecting changes and for caching.
+  typedef std::set<AccessPointData, AccessPointDataLess> AccessPointDataSet;
+  AccessPointDataSet access_point_data;
+};
+
+template<typename DataType>
+class DeviceDataProvider;
+
+// DeviceDataProvider uses containment to hide platform-specific implementation
+// details from common code. This class provides common functionality for these
+// contained implementation classes.
+template<typename DataType>
+class DeviceDataProviderImplBase {
+ public:
+  DeviceDataProviderImplBase() : container_(NULL) {}
+  virtual ~DeviceDataProviderImplBase() {}
+
+  virtual bool GetData(DataType *data) = 0;
+
+  // Sets the container of this class, which is of type DeviceDataProvider.
+  // This is required to pass as a parameter when making the callback to
+  // listeners.
+  void SetContainer(DeviceDataProvider<DataType> *container) {
+    container_ = container;
+  }
+
+  typedef typename DeviceDataProvider<DataType>::ListenerInterface
+          ListenerInterface;
+  void AddListener(ListenerInterface *listener) {
+    MutexLock mutex(&listeners_mutex_);
+    listeners_.insert(listener);
+  }
+  bool RemoveListener(ListenerInterface *listener) {
+    MutexLock mutex(&listeners_mutex_);
+    typename ListenersSet::iterator iter = find(listeners_.begin(),
+                                                listeners_.end(),
+                                                listener);
+    if (iter == listeners_.end()) {
+      return false;
+    }
+    listeners_.erase(iter);
+    return true;
+  }
+
+ protected:
+  // Calls DeviceDataUpdateAvailable() on all registered listeners.
+  typedef std::set<ListenerInterface*> ListenersSet;
+  void NotifyListeners() {
+    MutexLock lock(&listeners_mutex_);
+    for (typename ListenersSet::const_iterator iter = listeners_.begin();
+         iter != listeners_.end();
+         ++iter) {
+      (*iter)->DeviceDataUpdateAvailable(container_);
+    }
+  }
+
+ private:
+  DeviceDataProvider<DataType> *container_;
+
+  // The listeners to this class and their mutex.
+  ListenersSet listeners_;
+  Mutex listeners_mutex_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(DeviceDataProviderImplBase);
+};
+
+typedef DeviceDataProviderImplBase<RadioData> RadioDataProviderImplBase;
+typedef DeviceDataProviderImplBase<WifiData> WifiDataProviderImplBase;
+
+// A device data provider
+//
+// We use a singleton instance of this class which is shared by multiple network
+// location providers. These location providers access the instance through the
+// Register and Unregister methods.
+template<typename DataType>
+class DeviceDataProvider {
+ public:
+  // Interface to be implemented by listeners to a device data provider.
+  class ListenerInterface {
+   public:
+    virtual void DeviceDataUpdateAvailable(
+        DeviceDataProvider<DataType> *provider) = 0;
+    virtual ~ListenerInterface() {}
+  };
+
+  // Sets the factory function which will be used by Register to create the
+  // implementation used by the singleton instance. This factory approach is
+  // used to abastract accross both platform-specific implementation and to
+  // inject mock implementations for testing.
+  typedef DeviceDataProviderImplBase<DataType> *(*ImplFactoryFunction)(void);
+  static void SetFactory(ImplFactoryFunction factory_function_in) {
+    factory_function_ = factory_function_in;
+  }
+
+  static void ResetFactory() {
+    factory_function_ = DefaultFactoryFunction;
+  }
+
+  // Adds a listener, which will be called back with DeviceDataUpdateAvailable
+  // whenever new data is available. Returns the singleton instance.
+  static DeviceDataProvider *Register(ListenerInterface *listener) {
+    // We protect against Register and Unregister being called asynchronously
+    // from different threads. This is the case when a device data provider is
+    // used by a NetworkLocationProvider object. Register is always called from
+    // the JavaScript thread. Unregister is called when NetworkLocationProvider
+    // objects are destructed, which happens asynchronously once the
+    // NetworkLocationProvider HTTP request has completed.
+    MutexLock mutex(&instance_mutex_);
+    if (!instance_) {
+      instance_ = new DeviceDataProvider();
+    }
+    assert(instance_);
+    instance_->Ref();
+    instance_->AddListener(listener);
+    return instance_;
+  }
+
+  // Removes a listener. If this is the last listener, deletes the singleton
+  // instance. Return value indicates success.
+  static bool Unregister(ListenerInterface *listener) {
+    MutexLock mutex(&instance_mutex_);
+    if (!instance_->RemoveListener(listener)) {
+      return false;
+    }
+    if (instance_->Unref()) {
+      delete instance_;
+      instance_ = NULL;
+    }
+    return true;
+  }
+
+  // Provides whatever data the provider has, which may be nothing. Return
+  // value indicates whether this is all the data the provider could ever
+  // obtain.
+  bool GetData(DataType *data) {
+    return impl_->GetData(data);
+  }
+
+ private:
+  // Private constructor and destructor, callers access singleton through
+  // Register and Unregister.
+  DeviceDataProvider() {
+    assert(factory_function_);
+    impl_.reset((*factory_function_)());
+    impl_->SetContainer(this);
+  }
+  virtual ~DeviceDataProvider() {}
+
+  void Ref() {
+    count_.Ref();
+  }
+  // Returns true when the ref count transitions from 1 to 0.
+  bool Unref() {
+    return count_.Unref();
+  }
+
+  void AddListener(ListenerInterface *listener) {
+    impl_->AddListener(listener);
+  }
+
+  bool RemoveListener(ListenerInterface *listener) {
+    return impl_->RemoveListener(listener);
+  }
+
+  static DeviceDataProviderImplBase<DataType> *DefaultFactoryFunction();
+
+  // The singleton instance of this class and its mutex.
+  static DeviceDataProvider *instance_;
+  static Mutex instance_mutex_;
+
+  // The factory function used to create the singleton instance.
+  static ImplFactoryFunction factory_function_;
+
+  // The internal implementation.
+  scoped_ptr<DeviceDataProviderImplBase<DataType> > impl_;
+
+  RefCount count_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(DeviceDataProvider);
+};
+
+// static
+template<typename DataType>
+Mutex DeviceDataProvider<DataType>::instance_mutex_;
+
+// static
+template<typename DataType>
+DeviceDataProvider<DataType> *DeviceDataProvider<DataType>::instance_ =
+    NULL;
+
+// static
+template<typename DataType>
+typename DeviceDataProvider<DataType>::ImplFactoryFunction
+    DeviceDataProvider<DataType>::factory_function_ = DefaultFactoryFunction;
+
+typedef DeviceDataProvider<RadioData> RadioDataProvider;
+typedef DeviceDataProvider<WifiData> WifiDataProvider;
+
+#endif  // GEARS_GEOLOCATION_DEVICE_DATA_PROVIDER_H__
diff --git a/chrome/browser/geolocation/empty_device_data_provider.cc b/chrome/browser/geolocation/empty_device_data_provider.cc
new file mode 100644
index 0000000..9da8e831
--- /dev/null
+++ b/chrome/browser/geolocation/empty_device_data_provider.cc
@@ -0,0 +1,39 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Win32, Linux and OSX use the empty device data provider for radio data.
+#if (defined(WIN32) && !defined(OS_WINCE)) || \
+    defined(LINUX) || \
+    defined(OS_MACOSX)
+
+#include "gears/geolocation/empty_device_data_provider.h"
+
+// static
+template<>
+RadioDataProviderImplBase *RadioDataProvider::DefaultFactoryFunction() {
+  return new EmptyDeviceDataProvider<RadioData>();
+}
+
+#endif  // (WIN32 && !OS_WINCE) || LINUX || OS_MACOSX
diff --git a/chrome/browser/geolocation/empty_device_data_provider.h b/chrome/browser/geolocation/empty_device_data_provider.h
new file mode 100644
index 0000000..8c6097c
--- /dev/null
+++ b/chrome/browser/geolocation/empty_device_data_provider.h
@@ -0,0 +1,51 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GEARS_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H__
+#define GEARS_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H__
+
+#include "gears/geolocation/device_data_provider.h"
+
+// An implementation of DeviceDataProviderImplBase that does not provide any
+// data. Used on platforms where a given data type is not available.
+
+template<typename DataType>
+class EmptyDeviceDataProvider : public DeviceDataProviderImplBase<DataType> {
+ public:
+  EmptyDeviceDataProvider() {}
+  virtual ~EmptyDeviceDataProvider() {}
+
+  // DeviceDataProviderImplBase implementation
+  virtual bool GetData(DataType *data) {
+    assert(data);
+    // This is all the data we can get - nothing.
+    return true;
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(EmptyDeviceDataProvider);
+};
+
+#endif  // GEARS_GEOLOCATION_EMPTY_DEVICE_DATA_PROVIDER_H__
diff --git a/chrome/browser/geolocation/wifi_data_provider_common.cc b/chrome/browser/geolocation/wifi_data_provider_common.cc
new file mode 100644
index 0000000..7068bc4
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_common.cc
@@ -0,0 +1,95 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "gears/geolocation/wifi_data_provider_common.h"
+
+#include <assert.h>
+
+#if defined(WIN32) || defined(OS_MACOSX)
+
+#if defined(WIN32)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#include "gears/base/common/string_utils_osx.h"
+#include "gears/base/safari/scoped_cf.h"
+#include "third_party/scoped_ptr/scoped_ptr.h"  // For scoped_array
+#endif
+
+std::string16 MacAddressAsString16(const uint8 mac_as_int[6]) {
+  // mac_as_int is big-endian. Write in byte chunks.
+  // Format is XX-XX-XX-XX-XX-XX.
+  static const char16 *kMacFormatString =
+      STRING16(L"%02x-%02x-%02x-%02x-%02x-%02x");
+#ifdef OS_MACOSX
+  scoped_cftype<CFStringRef> format_string(CFStringCreateWithCharacters(
+      kCFAllocatorDefault,
+      kMacFormatString,
+      std::char_traits<char16>::length(kMacFormatString)));
+  scoped_cftype<CFStringRef> mac_string(CFStringCreateWithFormat(
+      kCFAllocatorDefault,
+      NULL,  // not implemented
+      format_string.get(),
+      mac_as_int[0], mac_as_int[1], mac_as_int[2],
+      mac_as_int[3], mac_as_int[4], mac_as_int[5]));
+  std::string16 mac;
+  CFStringRefToString16(mac_string.get(), &mac);
+  return mac;
+#else
+  char16 mac[18];
+#ifdef DEBUG
+  int num_characters =
+#endif
+      wsprintf(mac, kMacFormatString,
+               mac_as_int[0], mac_as_int[1], mac_as_int[2],
+               mac_as_int[3], mac_as_int[4], mac_as_int[5]);
+  assert(num_characters == 17);
+  return mac;
+#endif
+}
+
+#endif  // WIN32 || OS_MACOSX
+
+#if defined(WIN32) || defined(OS_MACOSX) || defined(LINUX)
+
+// These constants are defined for each platfrom in wifi_data_provider_xxx.cc.
+extern const int kDefaultPollingInterval;
+extern const int kNoChangePollingInterval;
+extern const int kTwoNoChangePollingInterval;
+
+int UpdatePollingInterval(int polling_interval, bool scan_results_differ) {
+  if (scan_results_differ) {
+    return kDefaultPollingInterval;
+  }
+  if (polling_interval == kDefaultPollingInterval) {
+    return kNoChangePollingInterval;
+  } else {
+    assert(polling_interval == kNoChangePollingInterval ||
+           polling_interval == kTwoNoChangePollingInterval);
+    return kTwoNoChangePollingInterval;
+  }
+}
+
+#endif  // WIN32 || OS_MACOSX || LINUX
diff --git a/chrome/browser/geolocation/wifi_data_provider_common.h b/chrome/browser/geolocation/wifi_data_provider_common.h
new file mode 100644
index 0000000..a8074b9
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_common.h
@@ -0,0 +1,39 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H__
+#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H__
+
+#include "gears/base/common/string16.h"
+#include "gears/base/common/basictypes.h"
+
+// Converts a MAC address stored as an array of uint8 to a string.
+std::string16 MacAddressAsString16(const uint8 mac_as_int[6]);
+
+// Calculates the new polling interval for wiFi scans, given the previous
+// interval and whether the last scan produced new results.
+int UpdatePollingInterval(int polling_interval, bool scan_results_differ);
+
+#endif  // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_COMMON_H__
diff --git a/chrome/browser/geolocation/wifi_data_provider_linux.cc b/chrome/browser/geolocation/wifi_data_provider_linux.cc
new file mode 100644
index 0000000..fd95a2c
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_linux.cc
@@ -0,0 +1,279 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// WiFi card drivers for Linux implement the Wireless Extensions interface.
+// This interface is part of the Linux kernel.
+//
+// Various sets of tools are available to manipulate the Wireless Extensions,
+// of which Wireless Tools is the default implementation. Wireless Tools
+// provides a C++ library (libiw) as well as a set of command line tools
+// (iwconfig, iwlist etc). See
+// http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html for details.
+//
+// Ideally, we would use libiw to obtain WiFi data. However, Wireless Tools is
+// released under GPL, which is not compatible with Gears. Furthermore, little
+// documentation is available for Wireless Extensions, so replicating libiw
+// without copying it directly would be difficult.
+//
+// We therefore simply invoke iwlist (one of the Wireless Tools command line
+// tools) and parse the output. Sample output is shown below.
+//
+// lo        Interface doesn't support scanning.
+//
+// ath0      Scan completed :
+//           Cell 01 - Address: 00:24:86:11:4C:42
+//                     ESSID:"Test SSID"
+//                     Mode:Master
+//                     Frequency:2.427 GHz (Channel 4)
+//                     Quality=5/94  Signal level=-90 dBm  Noise level=-95 dBm
+//                     Encryption key:off
+//                     Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s
+//                               11 Mb/s; 12 Mb/s; 18 Mb/s
+//                     Extra:bcn_int=100
+//           Cell 02 - Address: 00:24:86:11:6F:E2
+//                     ESSID:"Test SSID"
+//                     Mode:Master
+//                     Frequency:2.447 GHz (Channel 8)
+//                     Quality=4/94  Signal level=-91 dBm  Noise level=-95 dBm
+//                     Encryption key:off
+//                     Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s
+//                               11 Mb/s; 12 Mb/s; 18 Mb/s
+//                     Extra:bcn_int=100
+//
+// TODO(steveblock): Investigate the possibility of the author of Wireless Tools
+// releasing libiw under a Gears-compatible license.
+
+// TODO(cprince): remove platform-specific #ifdef guards when OS-specific
+// sources (e.g. WIN32_CPPSRCS) are implemented
+#if defined(LINUX) && !defined(OS_MACOSX)
+
+#include "gears/geolocation/wifi_data_provider_linux.h"
+
+#include <ctype.h>  // For isxdigit()
+#include <stdio.h>
+#include "gears/base/common/string_utils.h"
+#include "gears/geolocation/wifi_data_provider_common.h"
+
+// The time periods, in milliseconds, between successive polls of the wifi data.
+extern const int kDefaultPollingInterval = 10000;  // 10s
+extern const int kNoChangePollingInterval = 120000;  // 2 mins
+extern const int kTwoNoChangePollingInterval = 600000;  // 10 mins
+
+// Local function
+static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points);
+
+// static
+template<>
+WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() {
+  return new LinuxWifiDataProvider();
+}
+
+
+LinuxWifiDataProvider::LinuxWifiDataProvider()
+    : is_first_scan_complete_(false) {
+  Start();
+}
+
+LinuxWifiDataProvider::~LinuxWifiDataProvider() {
+  stop_event_.Signal();
+  Join();
+}
+
+bool LinuxWifiDataProvider::GetData(WifiData *data) {
+  assert(data);
+  MutexLock lock(&data_mutex_);
+  *data = wifi_data_;
+  // If we've successfully completed a scan, indicate that we have all of the
+  // data we can get.
+  return is_first_scan_complete_;
+}
+
+// Thread implementation
+void LinuxWifiDataProvider::Run() {
+  // Regularly get the access point data.
+  int polling_interval = kDefaultPollingInterval;
+  do {
+    WifiData new_data;
+    if (GetAccessPointData(&new_data.access_point_data)) {
+      bool update_available;
+      data_mutex_.Lock();
+      update_available = wifi_data_.DiffersSignificantly(new_data);
+      wifi_data_ = new_data;
+      data_mutex_.Unlock();
+      polling_interval =
+          UpdatePollingInterval(polling_interval, update_available);
+      if (update_available) {
+        is_first_scan_complete_ = true;
+        NotifyListeners();
+      }
+    }
+  } while (!stop_event_.WaitWithTimeout(polling_interval));
+}
+
+// Local functions
+
+static bool IsValidMacAddress(const char *mac_address) {
+  return isxdigit(mac_address[0]) &&
+         isxdigit(mac_address[1]) &&
+         mac_address[2] == ':' &&
+         isxdigit(mac_address[3]) &&
+         isxdigit(mac_address[4]) &&
+         mac_address[5] == ':' &&
+         isxdigit(mac_address[6]) &&
+         isxdigit(mac_address[7]) &&
+         mac_address[8] == ':' &&
+         isxdigit(mac_address[9]) &&
+         isxdigit(mac_address[10]) &&
+         mac_address[11] == ':' &&
+         isxdigit(mac_address[12]) &&
+         isxdigit(mac_address[13]) &&
+         mac_address[14] == ':' &&
+         isxdigit(mac_address[15]) &&
+         isxdigit(mac_address[16]);
+}
+
+static void ParseLine(const std::string &line,
+                      const std::string &mac_address_string,
+                      const std::string &ssid_string,
+                      const std::string &signal_strength_string,
+                      AccessPointData *access_point_data) {
+  // Currently we get only MAC address, SSID and signal strength.
+  // TODO(steveblock): Work out how to get age, channel and signal-to-noise.
+  std::string::size_type index;
+  if ((index = line.find(mac_address_string)) != std::string::npos) {
+    // MAC address
+    if (IsValidMacAddress(&line.at(index + mac_address_string.size()))) {
+      UTF8ToString16(&line.at(index + mac_address_string.size()),
+                     17,  // XX:XX:XX:XX:XX:XX
+                     &access_point_data->mac_address);
+    }
+  } else if ((index = line.find(ssid_string)) != std::string::npos) {
+    // SSID
+    // The string should be quoted.
+    std::string::size_type start = index + ssid_string.size() + 1;
+    std::string::size_type end = line.find('\"', start);
+    // If we can't find a trailing quote, something has gone wrong.
+    if (end != std::string::npos) {
+      UTF8ToString16(&line.at(start), end - start, &access_point_data->ssid);
+    }
+  } else if ((index = line.find(signal_strength_string)) != std::string::npos) {
+    // Signal strength
+    // iwlist will convert to dBm if it can. If it has failed to do so, we can't
+    // make use of the data.
+    if (line.find("dBm") != std::string::npos) {
+      // atoi will ignore trailing non-numeric characters
+      access_point_data->radio_signal_strength =
+          atoi(&line.at(index + signal_strength_string.size()));
+    }
+  }
+}
+
+static void ParseAccessPoint(const std::string &text,
+                             const std::string &mac_address_string,
+                             const std::string &ssid_string,
+                             const std::string &signal_strength_string,
+                             AccessPointData *access_point_data) {
+  // Split response into lines to aid parsing.
+  std::string::size_type start = 0;
+  std::string::size_type end;
+  do {
+    end = text.find('\n', start);
+    std::string::size_type length = (end == std::string::npos) ?
+                                    std::string::npos : end - start;
+    ParseLine(text.substr(start, length),
+              mac_address_string,
+              ssid_string,
+              signal_strength_string,
+              access_point_data);
+    start = end + 1;
+  } while (end != std::string::npos);
+}
+
+// Issues the specified command, and parses the response. Data for each access
+// point is separated by the given delimiter. Within each block of data, the
+// repsonse is split into lines and data is extracted by searching for the MAC
+// address, SSID and signal strength strings.
+bool IssueCommandAndParseResult(const char *command,
+                                const char *delimiter,
+                                const std::string &mac_address_string,
+                                const std::string &ssid_string,
+                                const std::string &signal_strength_string,
+                                WifiData::AccessPointDataSet *access_points) {
+  // Open pipe in read mode.
+  FILE *result_pipe = popen(command, "r");
+  if (result_pipe == NULL) {
+    LOG(("IssueCommand(): Failed to open pipe.\n"));
+    return false;
+  }
+
+  // Read results of command.
+  static const int kBufferSize = 1024;
+  char buffer[kBufferSize];
+  size_t bytes_read;
+  std::string result;
+  do {
+    bytes_read = fread(buffer, 1, kBufferSize, result_pipe);
+    result.append(buffer, bytes_read);
+  } while (static_cast<int>(bytes_read) == kBufferSize);
+  pclose(result_pipe);
+
+
+  // Parse results.
+  assert(access_points);
+  access_points->clear();
+  std::string::size_type start = result.find(delimiter);
+  while (start != std::string::npos) {
+    std::string::size_type end = result.find(delimiter, start + 1);
+    std::string::size_type length = (end == std::string::npos) ?
+                                    std::string::npos : end - start;
+    AccessPointData access_point_data;
+    ParseAccessPoint(result.substr(start, length),
+                     mac_address_string,
+                     ssid_string,
+                     signal_strength_string,
+                     &access_point_data);
+    access_points->insert(access_point_data);
+    start = end;
+  }
+
+  return !access_points->empty();
+}
+
+static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points) {
+  return IssueCommandAndParseResult("iwlist scan 2> /dev/null",
+                                    "Cell ",
+                                    "Address: ",
+                                    "ESSID:",
+                                    "Signal level=",
+                                    access_points) ||
+         IssueCommandAndParseResult("iwconfig 2> /dev/null",
+                                    "ESSID:\"",
+                                    "Access Point: ",
+                                    "ESSID:",
+                                    "Signal level=",
+                                    access_points);
+}
+
+#endif  // LINUX && !OS_MACOSX
diff --git a/chrome/browser/geolocation/wifi_data_provider_linux.h b/chrome/browser/geolocation/wifi_data_provider_linux.h
new file mode 100644
index 0000000..f635246
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_linux.h
@@ -0,0 +1,59 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H__
+#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H__
+
+#include "gears/base/common/common.h"
+#include "gears/base/common/event.h"
+#include "gears/base/common/mutex.h"
+#include "gears/base/common/thread.h"
+#include "gears/geolocation/device_data_provider.h"
+
+class LinuxWifiDataProvider
+    : public WifiDataProviderImplBase,
+      public Thread {
+ public:
+  LinuxWifiDataProvider();
+  virtual ~LinuxWifiDataProvider();
+
+  // WifiDataProviderImplBase implementation
+  virtual bool GetData(WifiData *data);
+
+ private:
+  // Thread implementation.
+  virtual void Run();
+
+  WifiData wifi_data_;
+  Mutex data_mutex_;
+  // Event signalled to shut down the thread that polls for wifi data.
+  Event stop_event_;
+  // Whether we've successfully completed a scan for WiFi data.
+  bool is_first_scan_complete_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(LinuxWifiDataProvider);
+};
+
+#endif  // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_LINUX_H__
diff --git a/chrome/browser/geolocation/wifi_data_provider_osx.cc b/chrome/browser/geolocation/wifi_data_provider_osx.cc
new file mode 100644
index 0000000..8dfa15d
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_osx.cc
@@ -0,0 +1,168 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// We use the OSX system API function WirelessScanSplit. This function is not
+// documented or included in the SDK, so we use a reverse-engineered header,
+// osx_wifi_.h. This file is taken from the iStumbler project
+// (http://www.istumbler.net).
+
+// TODO(cprince): remove platform-specific #ifdef guards when OS-specific
+// sources (e.g. WIN32_CPPSRCS) are implemented
+#ifdef OS_MACOSX
+
+#include "gears/geolocation/wifi_data_provider_osx.h"
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include "gears/base/common/string_utils.h"
+#include "gears/geolocation/wifi_data_provider_common.h"
+
+// The time periods, in milliseconds, between successive polls of the wifi data.
+extern const int kDefaultPollingInterval = 120000;  // 2 mins
+extern const int kNoChangePollingInterval = 300000;  // 5 mins
+extern const int kTwoNoChangePollingInterval = 600000;  // 10 mins
+
+// static
+template<>
+WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() {
+  return new OsxWifiDataProvider();
+}
+
+
+OsxWifiDataProvider::OsxWifiDataProvider() : is_first_scan_complete_(false) {
+  Start();
+}
+
+OsxWifiDataProvider::~OsxWifiDataProvider() {
+  stop_event_.Signal();
+  Join();
+}
+
+bool OsxWifiDataProvider::GetData(WifiData *data) {
+  assert(data);
+  MutexLock lock(&data_mutex_);
+  *data = wifi_data_;
+  // If we've successfully completed a scan, indicate that we have all of the
+  // data we can get.
+  return is_first_scan_complete_;
+}
+
+// Thread implementation
+void OsxWifiDataProvider::Run() {
+  void *apple_80211_library = dlopen(
+      "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
+      RTLD_LAZY);
+  if (!apple_80211_library) {
+    is_first_scan_complete_ = true;
+    return;
+  }
+
+  WirelessAttach_function_ = reinterpret_cast<WirelessAttachFunction>(
+      dlsym(apple_80211_library, "WirelessAttach"));
+  WirelessScanSplit_function_ = reinterpret_cast<WirelessScanSplitFunction>(
+      dlsym(apple_80211_library, "WirelessScanSplit"));
+  WirelessDetach_function_ = reinterpret_cast<WirelessDetachFunction>(
+      dlsym(apple_80211_library, "WirelessDetach"));
+  assert(WirelessAttach_function_ &&
+         WirelessScanSplit_function_ &&
+         WirelessDetach_function_);
+    
+  if ((*WirelessAttach_function_)(&wifi_context_, 0) != noErr) {
+    is_first_scan_complete_ = true;
+    return;
+  }
+
+  // Regularly get the access point data.
+  int polling_interval = kDefaultPollingInterval;
+  do {
+    WifiData new_data;
+    GetAccessPointData(&new_data.access_point_data);
+    bool update_available;
+    data_mutex_.Lock();
+    update_available = wifi_data_.DiffersSignificantly(new_data);
+    wifi_data_ = new_data;
+    data_mutex_.Unlock();
+    polling_interval =
+        UpdatePollingInterval(polling_interval, update_available);
+    if (update_available) {
+      is_first_scan_complete_ = true;
+      NotifyListeners();
+    }
+  } while (!stop_event_.WaitWithTimeout(polling_interval));
+
+  (*WirelessDetach_function_)(wifi_context_);
+
+  dlclose(apple_80211_library);
+}
+
+void OsxWifiDataProvider::GetAccessPointData(
+    WifiData::AccessPointDataSet *access_points) {
+  assert(access_points);
+  assert(WirelessScanSplit_function_);
+  CFArrayRef managed_access_points = NULL;
+  CFArrayRef adhoc_access_points = NULL;
+  if ((*WirelessScanSplit_function_)(wifi_context_,
+                                     &managed_access_points,
+                                     &adhoc_access_points,
+                                     0) != noErr) {
+    return;
+  }
+  
+  if (managed_access_points == NULL) {
+    return;
+  }
+
+  int num_access_points = CFArrayGetCount(managed_access_points);
+  for (int i = 0; i < num_access_points; ++i) {
+    const WirelessNetworkInfo *access_point_info =
+        reinterpret_cast<const WirelessNetworkInfo*>(
+        CFDataGetBytePtr(
+        reinterpret_cast<const CFDataRef>(
+        CFArrayGetValueAtIndex(managed_access_points, i))));
+        
+    // Currently we get only MAC address, signal strength, channel
+    // signal-to-noise and SSID
+    // TODO(steveblock): Work out how to get age.
+    AccessPointData access_point_data;
+    access_point_data.mac_address =
+        MacAddressAsString16(access_point_info->macAddress);
+    // WirelessNetworkInfo::signal appears to be signal strength in dBm.
+    access_point_data.radio_signal_strength = access_point_info->signal;
+    access_point_data.channel = access_point_info->channel;
+    // WirelessNetworkInfo::noise appears to be noise floor in dBm.
+    access_point_data.signal_to_noise = access_point_info->signal -
+                                        access_point_info->noise;
+    std::string16 ssid;
+    if (UTF8ToString16(reinterpret_cast<const char*>(access_point_info->name),
+                       access_point_info->nameLen,
+                       &ssid)) {
+      access_point_data.ssid = ssid;
+    }
+
+    access_points->insert(access_point_data);
+  }
+}
+
+#endif  // OS_MACOSX
diff --git a/chrome/browser/geolocation/wifi_data_provider_osx.h b/chrome/browser/geolocation/wifi_data_provider_osx.h
new file mode 100644
index 0000000..69fc7828
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_osx.h
@@ -0,0 +1,71 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_OSX_H__
+#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_OSX_H__
+
+#include "gears/base/common/common.h"
+#include "gears/base/common/event.h"
+#include "gears/base/common/mutex.h"
+#include "gears/base/common/thread.h"
+#include "gears/geolocation/device_data_provider.h"
+#include "gears/geolocation/osx_wifi.h"
+
+class OsxWifiDataProvider
+    : public WifiDataProviderImplBase,
+      public Thread {
+ public:
+  OsxWifiDataProvider();
+  virtual ~OsxWifiDataProvider();
+
+  // WifiDataProviderImplBase implementation.
+  virtual bool GetData(WifiData *data);
+
+ private:
+  // Thread implementation.
+  virtual void Run();
+  
+  void GetAccessPointData(WifiData::AccessPointDataSet *access_points);
+
+  // Context and function pointers for Apple80211 library.
+  WirelessContextPtr wifi_context_;
+  WirelessAttachFunction WirelessAttach_function_;
+  WirelessScanSplitFunction WirelessScanSplit_function_;
+  WirelessDetachFunction WirelessDetach_function_;
+
+  WifiData wifi_data_;
+  Mutex data_mutex_;
+
+  // Event signalled to shut down the thread that polls for wifi data.
+  Event stop_event_;
+
+  // Whether we've successfully completed a scan for WiFi data (or the polling
+  // thread has terminated early).
+  bool is_first_scan_complete_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(OsxWifiDataProvider);
+};
+
+#endif  // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_OSX_H__
diff --git a/chrome/browser/geolocation/wifi_data_provider_win.cc b/chrome/browser/geolocation/wifi_data_provider_win.cc
new file mode 100644
index 0000000..1e42105
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_win.cc
@@ -0,0 +1,534 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See
+// http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP
+// Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix)
+// also support a limited version of the WLAN API. See
+// http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses
+// wlanapi.h, which is not part of the SDK used by Gears, so is replicated
+// locally using data from the MSDN.
+//
+// Windows XP from Service Pack 2 onwards supports the Wireless Zero
+// Configuration (WZC) programming interface. See
+// http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx. 
+//
+// The MSDN recommends that one use the WLAN API where available, and WZC
+// otherwise.
+//
+// However, it seems that WZC fails for some wireless cards. Also, WLAN seems
+// not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly
+// otherwise.
+
+// TODO(cprince): remove platform-specific #ifdef guards when OS-specific
+// sources (e.g. WIN32_CPPSRCS) are implemented
+#if defined(WIN32) && !defined(OS_WINCE)
+
+#include "gears/geolocation/wifi_data_provider_win32.h"
+
+#include <windows.h>
+#include <ntddndis.h>  // For IOCTL_NDIS_QUERY_GLOBAL_STATS
+#include "gears/base/common/string_utils.h"
+#include "gears/base/common/vista_utils.h"
+#include "gears/geolocation/wifi_data_provider_common.h"
+#include "gears/geolocation/wifi_data_provider_windows_common.h"
+
+// Taken from ndis.h for WinCE.
+#define NDIS_STATUS_INVALID_LENGTH   ((NDIS_STATUS)0xC0010014L)
+#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
+
+// The limits on the size of the buffer used for the OID query.
+static const int kInitialBufferSize = 2 << 12;  // Good for about 50 APs.
+static const int kMaximumBufferSize = 2 << 20;  // 2MB
+
+// Length for generic string buffers passed to Win32 APIs.
+static const int kStringLength = 512;
+
+// The time periods, in milliseconds, between successive polls of the wifi data.
+extern const int kDefaultPollingInterval = 10000;  // 10s
+extern const int kNoChangePollingInterval = 120000;  // 2 mins
+extern const int kTwoNoChangePollingInterval = 600000;  // 10 mins
+
+// Local functions
+
+// Extracts data for an access point and converts to Gears format.
+static bool GetNetworkData(const WLAN_BSS_ENTRY &bss_entry,
+                           AccessPointData *access_point_data);
+bool UndefineDosDevice(const std::string16 &device_name);
+bool DefineDosDeviceIfNotExists(const std::string16 &device_name);
+HANDLE GetFileHandle(const std::string16 &device_name);
+// Makes the OID query and returns a Win32 error code.
+int PerformQuery(HANDLE adapter_handle,
+                 BYTE *buffer,
+                 DWORD buffer_size,
+                 DWORD *bytes_out);
+bool ResizeBuffer(int requested_size, BYTE **buffer);
+// Gets the system directory and appends a trailing slash if not already
+// present.
+bool GetSystemDirectory(std::string16 *path);
+
+// static
+template<>
+WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() {
+  return new Win32WifiDataProvider();
+}
+
+
+Win32WifiDataProvider::Win32WifiDataProvider()
+    : oid_buffer_size_(kInitialBufferSize),
+      is_first_scan_complete_(false) {
+  // Start the polling thread.
+  Start();
+}
+
+Win32WifiDataProvider::~Win32WifiDataProvider() {
+  stop_event_.Signal();
+  Join();
+}
+
+bool Win32WifiDataProvider::GetData(WifiData *data) {
+  assert(data);
+  MutexLock lock(&data_mutex_);
+  *data = wifi_data_;
+  // If we've successfully completed a scan, indicate that we have all of the
+  // data we can get.
+  return is_first_scan_complete_;
+}
+
+// Thread implementation
+void Win32WifiDataProvider::Run() {
+  // We use an absolute path to load the DLL to avoid DLL preloading attacks.
+  HINSTANCE library = NULL;
+  std::string16 system_directory;
+  if (GetSystemDirectory(&system_directory)) {
+    assert(!system_directory.empty());
+    std::string16 dll_path = system_directory + L"wlanapi.dll";
+    library = LoadLibraryEx(dll_path.c_str(),
+                            NULL,
+                            LOAD_WITH_ALTERED_SEARCH_PATH);
+  }
+
+  // Use the WLAN interface if we're on Vista and if it's available. Otherwise,
+  // use NDIS.
+  typedef bool (Win32WifiDataProvider::*GetAccessPointDataFunction)(
+      WifiData::AccessPointDataSet *data);
+  GetAccessPointDataFunction get_access_point_data_function = NULL;
+  if (VistaUtils::IsRunningOnVista() && library) {
+    GetWLANFunctions(library);
+    get_access_point_data_function =
+        &Win32WifiDataProvider::GetAccessPointDataWLAN;
+  } else {
+    // We assume the list of interfaces doesn't change while Gears is running.
+    if (!GetInterfacesNDIS()) {
+      is_first_scan_complete_ = true;
+      return;
+    }
+    get_access_point_data_function =
+        &Win32WifiDataProvider::GetAccessPointDataNDIS;
+  }
+  assert(get_access_point_data_function);
+
+  int polling_interval = kDefaultPollingInterval;
+  // Regularly get the access point data.
+  do {
+    WifiData new_data;
+    if ((this->*get_access_point_data_function)(&new_data.access_point_data)) {
+      bool update_available;
+      data_mutex_.Lock();
+      update_available = wifi_data_.DiffersSignificantly(new_data);
+      wifi_data_ = new_data;
+      data_mutex_.Unlock();
+      polling_interval =
+          UpdatePollingInterval(polling_interval, update_available);
+      if (update_available) {
+        is_first_scan_complete_ = true;
+        NotifyListeners();
+      }
+    }
+  } while (!stop_event_.WaitWithTimeout(polling_interval));
+
+  FreeLibrary(library);
+}
+
+// WLAN functions
+
+void Win32WifiDataProvider::GetWLANFunctions(HINSTANCE wlan_library) {
+  assert(wlan_library);
+  WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>(
+      GetProcAddress(wlan_library, "WlanOpenHandle"));
+  WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>(
+      GetProcAddress(wlan_library, "WlanEnumInterfaces"));
+  WlanGetNetworkBssList_function_ =
+      reinterpret_cast<WlanGetNetworkBssListFunction>(
+      GetProcAddress(wlan_library, "WlanGetNetworkBssList"));
+  WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>(
+      GetProcAddress(wlan_library, "WlanFreeMemory"));
+  WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>(
+      GetProcAddress(wlan_library, "WlanCloseHandle"));
+  assert(WlanOpenHandle_function_ &&
+         WlanEnumInterfaces_function_ &&
+         WlanGetNetworkBssList_function_ &&
+         WlanFreeMemory_function_ &&
+         WlanCloseHandle_function_);
+}
+
+bool Win32WifiDataProvider::GetAccessPointDataWLAN(
+    WifiData::AccessPointDataSet *data) {
+  assert(data);
+
+  // Get the handle to the WLAN API.
+  DWORD negotiated_version;
+  HANDLE wlan_handle = NULL;
+  // We could be executing on either Windows XP or Windows Vista, so use the
+  // lower version of the client WLAN API. It seems that the negotiated version
+  // is the Vista version irrespective of what we pass!
+  static const int kXpWlanClientVersion = 1;
+  if ((*WlanOpenHandle_function_)(kXpWlanClientVersion,
+                                  NULL,
+                                  &negotiated_version,
+                                  &wlan_handle) != ERROR_SUCCESS) {
+    return false;
+  }
+  assert(wlan_handle);
+
+  // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
+  WLAN_INTERFACE_INFO_LIST *interface_list = NULL;
+  if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) !=
+      ERROR_SUCCESS) {
+    return false;
+  }
+  assert(interface_list);
+
+  // Go through the list of interfaces and get the data for each.
+  for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) {
+    GetInterfaceDataWLAN(wlan_handle,
+                         interface_list->InterfaceInfo[i].InterfaceGuid,
+                         data);
+  }
+
+  // Free interface_list.
+  (*WlanFreeMemory_function_)(interface_list);
+
+  // Close the handle.
+  if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) {
+    return false;
+  }
+
+  return true;
+}
+
+// Appends the data for a single interface to the data vector. Returns the
+// number of access points found, or -1 on error.
+int Win32WifiDataProvider::GetInterfaceDataWLAN(
+    const HANDLE wlan_handle,
+    const GUID &interface_id,
+    WifiData::AccessPointDataSet *data) {
+  assert(data);
+  // WlanGetNetworkBssList allocates bss_list.
+  WLAN_BSS_LIST *bss_list;
+  if ((*WlanGetNetworkBssList_function_)(wlan_handle,
+                                         &interface_id,
+                                         NULL,   // Use all SSIDs.
+                                         DOT11_BSS_TYPE_UNUSED,
+                                         false,  // bSecurityEnabled - unused
+                                         NULL,   // reserved
+                                         &bss_list) != ERROR_SUCCESS) {
+    return -1;
+  }
+
+  int found = 0;
+  for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) {
+    AccessPointData access_point_data;
+    if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) {
+      ++found;
+      data->insert(access_point_data);
+    }
+  }
+
+  (*WlanFreeMemory_function_)(bss_list);
+
+  return found;
+}
+
+// NDIS functions
+
+bool Win32WifiDataProvider::GetInterfacesNDIS() {
+  HKEY network_cards_key = NULL;
+  if (RegOpenKeyEx(
+      HKEY_LOCAL_MACHINE,
+      L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
+      0,
+      KEY_READ,
+      &network_cards_key) != ERROR_SUCCESS) {
+    return false;
+  }
+  assert(network_cards_key);
+
+  for (int i = 0; ; ++i) {
+    TCHAR name[kStringLength];
+    DWORD name_size = kStringLength;
+    FILETIME time;
+    if (RegEnumKeyEx(network_cards_key,
+                     i,
+                     name,
+                     &name_size,
+                     NULL,
+                     NULL,
+                     NULL,
+                     &time) != ERROR_SUCCESS) {
+      break;
+    }
+    HKEY hardware_key = NULL;
+    if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) !=
+        ERROR_SUCCESS) {
+      break;
+    }
+    assert(hardware_key);
+
+    TCHAR service_name[kStringLength];
+    DWORD service_name_size = kStringLength;
+    DWORD type = 0;
+    if (RegQueryValueEx(hardware_key,
+                        L"ServiceName",
+                        NULL,
+                        &type,
+                        reinterpret_cast<LPBYTE>(service_name),
+                        &service_name_size) == ERROR_SUCCESS) {
+      interface_service_names_.push_back(service_name);
+    }
+    RegCloseKey(hardware_key);
+  }
+
+  RegCloseKey(network_cards_key);
+  return true;
+}
+
+bool Win32WifiDataProvider::GetAccessPointDataNDIS(
+    WifiData::AccessPointDataSet *data) {
+  assert(data);
+
+  for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) {
+    // First, check that we have a DOS device for this adapter.
+    if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) {
+      continue;
+    }
+
+    // Get the handle to the device. This will fail if the named device is not
+    // valid.
+    HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]);
+    if (adapter_handle == INVALID_HANDLE_VALUE) {
+      continue;
+    }
+
+    // Get the data.
+    GetInterfaceDataNDIS(adapter_handle, data);
+
+    // Clean up.
+    CloseHandle(adapter_handle);
+    UndefineDosDevice(interface_service_names_[i]);
+  }
+
+  return true;
+}
+
+bool Win32WifiDataProvider::GetInterfaceDataNDIS(
+    HANDLE adapter_handle,
+    WifiData::AccessPointDataSet *data) {
+  assert(data);
+
+  BYTE *buffer = reinterpret_cast<BYTE*>(malloc(oid_buffer_size_));
+  if (buffer == NULL) {
+    return false;
+  }
+
+  DWORD bytes_out;
+  int result;
+
+  while (true) {
+    bytes_out = 0;
+    result = PerformQuery(adapter_handle, buffer, oid_buffer_size_, &bytes_out);
+    if (result == ERROR_GEN_FAILURE ||  // Returned by some Intel cards.
+        result == ERROR_INSUFFICIENT_BUFFER ||
+        result == ERROR_MORE_DATA ||
+        result == NDIS_STATUS_INVALID_LENGTH ||
+        result == NDIS_STATUS_BUFFER_TOO_SHORT) {
+      // The buffer we supplied is too small, so increase it. bytes_out should
+      // provide the required buffer size, but this is not always the case.
+      if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) {
+        oid_buffer_size_ = bytes_out;
+      } else {
+        oid_buffer_size_ *= 2;
+      }
+      if (!ResizeBuffer(oid_buffer_size_, &buffer)) {
+        oid_buffer_size_ = kInitialBufferSize;  // Reset for next time.
+        return false;
+      }
+    } else {
+      // The buffer is not too small.
+      break;
+    }
+  }
+  assert(buffer);
+
+  if (result == ERROR_SUCCESS) {
+    NDIS_802_11_BSSID_LIST* bssid_list =
+        reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer);
+    GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data);
+  }
+
+  free(buffer);
+  return true;
+}
+
+// Local functions
+
+static bool GetNetworkData(const WLAN_BSS_ENTRY &bss_entry,
+                           AccessPointData *access_point_data) {
+  // Currently we get only MAC address, signal strength and SSID.
+  assert(access_point_data);
+  access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid);
+  access_point_data->radio_signal_strength = bss_entry.lRssi;
+  // bss_entry.dot11Ssid.ucSSID is not null-terminated.
+  UTF8ToString16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID),
+                 static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength),
+                 &access_point_data->ssid);
+  // TODO(steveblock): Is it possible to get the following?
+  //access_point_data->signal_to_noise
+  //access_point_data->age
+  //access_point_data->channel
+  return true;
+}
+
+bool UndefineDosDevice(const std::string16 &device_name) {
+  // We remove only the mapping we use, that is \Device\<device_name>.
+  std::string16 target_path = L"\\Device\\" + device_name;
+  return DefineDosDevice(
+      DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
+      device_name.c_str(),
+      target_path.c_str()) == TRUE;
+}
+
+bool DefineDosDeviceIfNotExists(const std::string16 &device_name) {
+  // We create a DOS device name for the device at \Device\<device_name>.
+  std::string16 target_path = L"\\Device\\" + device_name;
+
+  TCHAR target[kStringLength];
+  if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
+      target_path.compare(target) == 0) {
+    // Device already exists.
+    return true;
+  }
+
+  if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+    return false;
+  }
+
+  if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
+                       device_name.c_str(),
+                       target_path.c_str())) {
+    return false;
+  }
+
+  // Check that the device is really there.
+  return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
+      target_path.compare(target) == 0;
+}
+
+HANDLE GetFileHandle(const std::string16 &device_name) {
+  // We access a device with DOS path \Device\<device_name> at
+  // \\.\<device_name>.
+  std::string16 formatted_device_name = L"\\\\.\\" + device_name;
+
+  return CreateFile(formatted_device_name.c_str(),
+                    GENERIC_READ,
+                    FILE_SHARE_READ | FILE_SHARE_WRITE,  // share mode
+                    0,  // security attributes
+                    OPEN_EXISTING,
+                    0,  // flags and attributes
+                    INVALID_HANDLE_VALUE);
+}
+
+int PerformQuery(HANDLE adapter_handle,
+                 BYTE *buffer,
+                 DWORD buffer_size,
+                 DWORD *bytes_out) {
+  DWORD oid = OID_802_11_BSSID_LIST;
+  if (!DeviceIoControl(adapter_handle,
+                       IOCTL_NDIS_QUERY_GLOBAL_STATS,
+                       &oid,
+                       sizeof(oid),
+                       buffer,
+                       buffer_size,
+                       bytes_out,
+                       NULL)) {
+    return GetLastError();
+  }
+  return ERROR_SUCCESS;
+}
+
+bool ResizeBuffer(int requested_size, BYTE **buffer) {
+  if (requested_size > kMaximumBufferSize) {
+    free(*buffer);
+    *buffer = NULL;
+    return false;
+  }
+
+  BYTE *new_buffer = reinterpret_cast<BYTE*>(realloc(*buffer, requested_size));
+  if (new_buffer == NULL) {
+    free(*buffer);
+    *buffer = NULL;
+    return false;
+  }
+
+  *buffer = new_buffer;
+  return true;
+}
+
+bool GetSystemDirectory(std::string16 *path) {
+  assert(path);
+  // Return value includes terminating NULL.
+  int buffer_size = GetSystemDirectory(NULL, 0);
+  if (buffer_size == 0) {
+    return false;
+  }
+  char16 *buffer = new char16[buffer_size];
+
+  // Return value excludes terminating NULL.
+  int characters_written = GetSystemDirectory(buffer, buffer_size);
+  if (characters_written == 0) {
+    return false;
+  }
+  assert(characters_written == buffer_size - 1);
+
+  path->assign(buffer);
+  delete[] buffer;
+
+  if (path->at(path->length() - 1) != L'\\') {
+    path->append(L"\\");
+  }
+  return true;
+}
+
+#endif  // WIN32 && !OS_WINCE
diff --git a/chrome/browser/geolocation/wifi_data_provider_win.h b/chrome/browser/geolocation/wifi_data_provider_win.h
new file mode 100644
index 0000000..81b2274
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_win.h
@@ -0,0 +1,87 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WIN32_H__
+#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WIN32_H__
+
+#include <vector>
+#include "gears/base/common/common.h"
+#include "gears/base/common/thread.h"
+#include "gears/geolocation/device_data_provider.h"
+#include "gears/geolocation/wlanapi.h"
+
+class Win32WifiDataProvider
+    : public WifiDataProviderImplBase,
+      public Thread {
+ public:
+  Win32WifiDataProvider();
+  virtual ~Win32WifiDataProvider();
+
+  // WifiDataProviderImplBase implementation
+  virtual bool GetData(WifiData *data);
+
+ private:
+  // Thread implementation
+  virtual void Run();
+
+  // WLAN methods
+  // Loads the required functions from the DLL.
+  void GetWLANFunctions(HINSTANCE wlan_library);
+  // Gets wifi data for all visible access points.
+  bool GetAccessPointDataWLAN(WifiData::AccessPointDataSet *data);
+  int GetInterfaceDataWLAN(HANDLE wlan_handle,
+                           const GUID &interface_id,
+                           WifiData::AccessPointDataSet *data);
+
+  // NDIS methods.
+  bool GetInterfacesNDIS();
+  bool GetAccessPointDataNDIS(WifiData::AccessPointDataSet *data);
+  bool GetInterfaceDataNDIS(HANDLE adapter_handle,
+                            WifiData::AccessPointDataSet *data);
+
+  // Function pointers for WLAN
+  WlanOpenHandleFunction WlanOpenHandle_function_;
+  WlanEnumInterfacesFunction WlanEnumInterfaces_function_;
+  WlanGetNetworkBssListFunction WlanGetNetworkBssList_function_;
+  WlanFreeMemoryFunction WlanFreeMemory_function_;
+  WlanCloseHandleFunction WlanCloseHandle_function_;
+
+  // NDIS variables.
+  std::vector<std::string16> interface_service_names_;
+  int oid_buffer_size_;
+
+  WifiData wifi_data_;
+  Mutex data_mutex_;
+  // Events signalled to shut down the thread that polls for wifi data.
+  Event stop_event_;
+
+  // Whether we've successfully completed a scan for WiFi data (or the polling
+  // thread has terminated early).
+  bool is_first_scan_complete_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Win32WifiDataProvider);
+};
+
+#endif  // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WIN32_H__
diff --git a/chrome/browser/geolocation/wifi_data_provider_windows_common.cc b/chrome/browser/geolocation/wifi_data_provider_windows_common.cc
new file mode 100644
index 0000000..d367c90
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_windows_common.cc
@@ -0,0 +1,76 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#if defined(WIN32) || defined(OS_WINCE)
+
+#include "gears/geolocation/wifi_data_provider_windows_common.h"
+
+#include <assert.h>
+#include "gears/base/common/string_utils.h"
+#include "gears/geolocation/device_data_provider.h"
+#include "gears/geolocation/wifi_data_provider_common.h"
+
+bool ConvertToGearsFormat(const NDIS_WLAN_BSSID &data,
+                          AccessPointData *access_point_data) {
+  // Currently we get only MAC address, signal strength and SSID.
+  // TODO(steveblock): Work out how to get age, channel and signal-to-noise.
+  assert(access_point_data);
+  access_point_data->mac_address = MacAddressAsString16(data.MacAddress);
+  access_point_data->radio_signal_strength = data.Rssi;
+  // Note that _NDIS_802_11_SSID::Ssid::Ssid is not null-terminated.
+  UTF8ToString16(reinterpret_cast<const char*>(data.Ssid.Ssid),
+                 data.Ssid.SsidLength,
+                 &access_point_data->ssid);
+  return true;
+}
+
+int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST &bss_id_list,
+                         int list_size,
+                         WifiData::AccessPointDataSet *data) {
+  // Walk through the BSS IDs.
+  int found = 0;
+  const uint8 *iterator = reinterpret_cast<const uint8*>(&bss_id_list.Bssid[0]);
+  const uint8 *end_of_buffer =
+      reinterpret_cast<const uint8*>(&bss_id_list) + list_size;
+  for (int i = 0; i < static_cast<int>(bss_id_list.NumberOfItems); ++i) {
+    const NDIS_WLAN_BSSID *bss_id =
+        reinterpret_cast<const NDIS_WLAN_BSSID*>(iterator);
+    // Check that the length of this BSS ID is reasonable.
+    if (bss_id->Length < sizeof(NDIS_WLAN_BSSID) ||
+        iterator + bss_id->Length > end_of_buffer) {
+      break;
+    }
+    AccessPointData access_point_data;
+    if (ConvertToGearsFormat(*bss_id, &access_point_data)) {
+      data->insert(access_point_data);
+      ++found;
+    }
+    // Move to the next BSS ID.
+    iterator += bss_id->Length;
+  }
+  return found;
+}
+
+#endif  // WIN32 || OS_WINCE
diff --git a/chrome/browser/geolocation/wifi_data_provider_windows_common.h b/chrome/browser/geolocation/wifi_data_provider_windows_common.h
new file mode 100644
index 0000000..e2e0873
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_windows_common.h
@@ -0,0 +1,45 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file contains functions which are common to both the WIN32 and WINCE
+// implementations of the wifi data provider.
+
+#ifndef GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WINDOWS_COMMON_H__
+#define GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WINDOWS_COMMON_H__
+
+#include <windows.h>
+#include <ntddndis.h>
+#include <vector>
+#include "gears/geolocation/device_data_provider.h"
+
+
+// Extracts access point data from the NDIS_802_11_BSSID_LIST structure and
+// appends it to the data vector. Returns the number of access points for which
+// data was extracted.
+int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST &bss_id_list,
+                         int list_size,
+                         WifiData::AccessPointDataSet *data);
+
+#endif  // GEARS_GEOLOCATION_WIFI_DATA_PROVIDER_WINDOWS_COMMON_H__
-- 
cgit v1.1