diff options
Diffstat (limited to 'chrome/browser/geolocation/wifi_data_provider_mac.cc')
-rw-r--r-- | chrome/browser/geolocation/wifi_data_provider_mac.cc | 184 |
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>; +} |