summaryrefslogtreecommitdiffstats
path: root/chrome/browser/geolocation/wifi_data_provider_mac.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/geolocation/wifi_data_provider_mac.cc')
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_mac.cc184
1 files changed, 184 insertions, 0 deletions
diff --git a/chrome/browser/geolocation/wifi_data_provider_mac.cc b/chrome/browser/geolocation/wifi_data_provider_mac.cc
new file mode 100644
index 0000000..f99b45f
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_mac.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// For OSX 10.5 we use the 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).
+
+#include "chrome/browser/geolocation/wifi_data_provider_mac.h"
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/geolocation/osx_wifi.h"
+#include "chrome/browser/geolocation/wifi_data_provider_common.h"
+
+namespace {
+// The time periods, in milliseconds, between successive polls of the wifi data.
+const int kDefaultPollingInterval = 120000; // 2 mins
+const int kNoChangePollingInterval = 300000; // 5 mins
+const int kTwoNoChangePollingInterval = 600000; // 10 mins
+const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
+
+// Provides the wifi API binding for use when running on OSX 10.5 machines using
+// the Apple80211 framework.
+class Apple80211Api : public WifiDataProviderCommon::WlanApiInterface {
+ public:
+ Apple80211Api();
+ virtual ~Apple80211Api();
+
+ // Must be called before any other interface method. Will return false if the
+ // Apple80211 framework cannot be initialized (e.g. running on post-10.5 OSX),
+ // in which case no other method may be called.
+ bool Init();
+
+ // WlanApiInterface
+ virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
+
+ private:
+ // Handle, context and function pointers for Apple80211 library.
+ void* apple_80211_library_;
+ WirelessContext* wifi_context_;
+ WirelessAttachFunction WirelessAttach_function_;
+ WirelessScanSplitFunction WirelessScanSplit_function_;
+ WirelessDetachFunction WirelessDetach_function_;
+
+ WifiData wifi_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(Apple80211Api);
+};
+
+Apple80211Api::Apple80211Api()
+ : apple_80211_library_(NULL), wifi_context_(NULL),
+ WirelessAttach_function_(NULL), WirelessScanSplit_function_(NULL),
+ WirelessDetach_function_(NULL) {
+}
+
+Apple80211Api::~Apple80211Api() {
+ if (WirelessDetach_function_)
+ (*WirelessDetach_function_)(wifi_context_);
+ dlclose(apple_80211_library_);
+}
+
+bool Apple80211Api::Init() {
+ DLOG(INFO) << "Apple80211Api::Init";
+ apple_80211_library_ = dlopen(
+ "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
+ RTLD_LAZY);
+ if (!apple_80211_library_) {
+ DLOG(WARNING) << "Could not open Apple80211 library";
+ return false;
+ }
+ 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"));
+ DCHECK(WirelessAttach_function_);
+ DCHECK(WirelessScanSplit_function_);
+ DCHECK(WirelessDetach_function_);
+
+ if (!WirelessAttach_function_ || !WirelessScanSplit_function_ ||
+ !WirelessDetach_function_) {
+ DLOG(WARNING) << "Symbol error. Attach: " << !!WirelessAttach_function_
+ << " Split: " << !!WirelessScanSplit_function_
+ << " Detach: " << !!WirelessDetach_function_;
+ return false;
+ }
+
+ WIErr err = (*WirelessAttach_function_)(&wifi_context_, 0);
+ if (err != noErr) {
+ DLOG(WARNING) << "Error attaching: " << err;
+ return false;
+ }
+ return true;
+}
+
+bool Apple80211Api::GetAccessPointData(WifiData::AccessPointDataSet* data) {
+ DLOG(INFO) << "Apple80211Api::GetAccessPointData";
+ DCHECK(data);
+ DCHECK(WirelessScanSplit_function_);
+ CFArrayRef managed_access_points = NULL;
+ CFArrayRef adhoc_access_points = NULL;
+ WIErr err = (*WirelessScanSplit_function_)(wifi_context_,
+ &managed_access_points,
+ &adhoc_access_points,
+ 0);
+ if (err != noErr) {
+ DLOG(WARNING) << "Error spliting scan: " << err;
+ return false;
+ }
+
+ if (managed_access_points == NULL) {
+ DLOG(WARNING) << "managed_access_points == NULL";
+ return false;
+ }
+
+ int num_access_points = CFArrayGetCount(managed_access_points);
+ DLOG(INFO) << "Found " << num_access_points << " 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
+ 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;
+ if (!UTF8ToUTF16(reinterpret_cast<const char*>(access_point_info->name),
+ access_point_info->nameLen,
+ &access_point_data.ssid)) {
+ access_point_data.ssid.clear();
+ }
+ data->insert(access_point_data);
+ }
+ return true;
+}
+} // namespace
+
+// static
+template<>
+WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
+ return new MacWifiDataProvider();
+}
+
+MacWifiDataProvider::MacWifiDataProvider() {
+}
+
+MacWifiDataProvider::~MacWifiDataProvider() {
+}
+
+MacWifiDataProvider::WlanApiInterface* MacWifiDataProvider::NewWlanApi() {
+ // Try and find a API binding that works: first try the officially supported
+ // CoreWLAN API, and if this fails (e.g. on OSX 10.5) fall back to the reverse
+ // engineered Apple80211 API.
+ MacWifiDataProvider::WlanApiInterface* core_wlan_api = NewCoreWlanApi();
+ if (core_wlan_api)
+ return core_wlan_api;
+
+ scoped_ptr<Apple80211Api> wlan_api(new Apple80211Api);
+ if (wlan_api->Init())
+ return wlan_api.release();
+
+ DLOG(INFO) << "MacWifiDataProvider : failed to initialize any wlan api";
+ return NULL;
+}
+
+PollingPolicyInterface* MacWifiDataProvider::NewPollingPolicy() {
+ return new GenericPollingPolicy<kDefaultPollingInterval,
+ kNoChangePollingInterval,
+ kTwoNoChangePollingInterval,
+ kNoWifiPollingIntervalMilliseconds>;
+}