summaryrefslogtreecommitdiffstats
path: root/chrome/browser/geolocation
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-08 11:11:24 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-08 11:11:24 +0000
commit5eaf62787c9cbe75a8e016666d6dddf592e693b1 (patch)
treed54e09340ca6a613fc00f61f81978041cdab8f91 /chrome/browser/geolocation
parent3b930768ef8432b472a12d44d84b9fe6555b4ba9 (diff)
downloadchromium_src-5eaf62787c9cbe75a8e016666d6dddf592e693b1.zip
chromium_src-5eaf62787c9cbe75a8e016666d6dddf592e693b1.tar.gz
chromium_src-5eaf62787c9cbe75a8e016666d6dddf592e693b1.tar.bz2
Add support for geolocation wifi scanning on OSX 10.6
BUG=http://crbug.com/37198 TEST=Run browser with --enable-geolocation on OSX 10.6, open maps.google.com Review URL: http://codereview.chromium.org/669083 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40891 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/geolocation')
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_corewlan_mac.mm156
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_mac.cc62
-rw-r--r--chrome/browser/geolocation/wifi_data_provider_mac.h15
3 files changed, 200 insertions, 33 deletions
diff --git a/chrome/browser/geolocation/wifi_data_provider_corewlan_mac.mm b/chrome/browser/geolocation/wifi_data_provider_corewlan_mac.mm
new file mode 100644
index 0000000..da960fc
--- /dev/null
+++ b/chrome/browser/geolocation/wifi_data_provider_corewlan_mac.mm
@@ -0,0 +1,156 @@
+// 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.
+
+// Implements a WLAN API binding for CoreWLAN, as available on OSX 10.6
+
+#include "chrome/browser/geolocation/wifi_data_provider_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/scoped_nsautorelease_pool.h"
+#include "base/scoped_nsobject.h"
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+// If building on 10.6 we can include the framework header directly.
+#import <CoreWLAN/CoreWLAN.h>
+
+#else
+// Otherwise just define the interfaces we require. Class definitions required
+// as we treat warnings as errors so we can't pass message to an untyped id.
+
+@interface CWInterface : NSObject
++ (CWInterface*)interface;
+- (NSArray*)scanForNetworksWithParameters:(NSDictionary*)parameters
+ error:(NSError**)error;
+@end
+
+@interface CWNetwork : NSObject <NSCopying, NSCoding>
+@property(readonly) NSString* ssid;
+@property(readonly) NSString* bssid;
+@property(readonly) NSData* bssidData;
+@property(readonly) NSNumber* securityMode;
+@property(readonly) NSNumber* phyMode;
+@property(readonly) NSNumber* channel;
+@property(readonly) NSNumber* rssi;
+@property(readonly) NSNumber* noise;
+@property(readonly) NSData* ieData;
+@property(readonly) BOOL isIBSS;
+- (BOOL)isEqualToNetwork:(CWNetwork*)network;
+@end
+
+// String literals derived empirically on an OSX 10.6 machine (XCode 3.2.1).
+// Commented out to avoid unused variables warnings; comment back in as needed.
+
+// static const NSString* kCWAssocKey8021XProfile = @"ASSOC_KEY_8021X_PROFILE";
+// static const NSString* kCWAssocKeyPassphrase = @"ASSOC_KEY_PASSPHRASE";
+// static const NSString* kCWBSSIDDidChangeNotification =
+// @"BSSID_CHANGED_NOTIFICATION";
+// static const NSString* kCWCountryCodeDidChangeNotification =
+// @"COUNTRY_CODE_CHANGED_NOTIFICATION";
+// static const NSString* kCWErrorDomain = @"APPLE80211_ERROR_DOMAIN";
+// static const NSString* kCWIBSSKeyChannel = @"IBSS_KEY_CHANNEL";
+// static const NSString* kCWIBSSKeyPassphrase = @"IBSS_KEY_PASSPHRASE";
+// static const NSString* kCWIBSSKeySSID = @"IBSS_KEY_SSID";
+// static const NSString* kCWLinkDidChangeNotification =
+// @"LINK_CHANGED_NOTIFICATION";
+// static const NSString* kCWModeDidChangeNotification =
+// @"MODE_CHANGED_NOTIFICATION";
+// static const NSString* kCWPowerDidChangeNotification =
+// @"POWER_CHANGED_NOTIFICATION";
+// static const NSString* kCWScanKeyBSSID = @"BSSID";
+// static const NSString* kCWScanKeyDwellTime = @"SCAN_DWELL_TIME";
+static const NSString* kCWScanKeyMerge = @"SCAN_MERGE";
+// static const NSString* kCWScanKeyRestTime = @"SCAN_REST_TIME";
+// static const NSString* kCWScanKeyScanType = @"SCAN_TYPE";
+// static const NSString* kCWScanKeySSID = @"SSID_STR";
+// static const NSString* kCWSSIDDidChangeNotification =
+// @"SSID_CHANGED_NOTIFICATION";
+
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+
+class CoreWlanApi : public WifiDataProviderCommon::WlanApiInterface {
+ public:
+ CoreWlanApi() {}
+
+ // Must be called before any other interface method. Will return false if the
+ // CoreWLAN framework cannot be initialized (e.g. running on pre-10.6 OSX),
+ // in which case no other method may be called.
+ bool Init();
+
+ // WlanApiInterface
+ virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data);
+
+ private:
+ scoped_nsobject<NSBundle> bundle_;
+ scoped_nsobject<CWInterface> corewlan_interface_;
+
+ DISALLOW_COPY_AND_ASSIGN(CoreWlanApi);
+};
+
+bool CoreWlanApi::Init() {
+ // As the WLAN api binding runs on its own thread, we need to provide our own
+ // auto release pool. It's simplest to do this as an automatic variable in
+ // each method that needs it, to ensure the scoping is correct and does not
+ // interfere with any other code using autorelease pools on the thread.
+ base::ScopedNSAutoreleasePool auto_pool;
+ bundle_.reset([[NSBundle alloc]
+ initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"]);
+ if (!bundle_) {
+ DLOG(INFO) << "Failed to load the CoreWLAN framework bundle";
+ return false;
+ }
+ corewlan_interface_.reset([[bundle_ classNamed:@"CWInterface"] interface]);
+ if (!corewlan_interface_) {
+ DLOG(INFO) << "Failed to create the CWInterface instance";
+ return false;
+ }
+ [corewlan_interface_ retain];
+ return true;
+}
+
+bool CoreWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
+ base::ScopedNSAutoreleasePool auto_pool;
+ DCHECK(corewlan_interface_);
+ NSError* err = nil;
+ // Initialize the scan parameters with scan key merging disabled, so we get
+ // every AP listed in the scan without any SSID de-duping logic.
+ NSDictionary* params =
+ [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]
+ forKey:kCWScanKeyMerge];
+
+ NSArray* scan = [corewlan_interface_ scanForNetworksWithParameters:params
+ error:&err];
+
+ const int error_code = [err code];
+ const int count = [scan count];
+ if (error_code && !count) {
+ DLOG(WARNING) << "CoreWLAN scan failed " << error_code;
+ return false;
+ }
+ DLOG(INFO) << "Found " << count << " wifi APs";
+
+ for (CWNetwork* network in scan) {
+ DCHECK(network);
+ AccessPointData access_point_data;
+ NSData* mac = [network bssidData];
+ DCHECK([mac length] == 6);
+ access_point_data.mac_address = MacAddressAsString16(
+ static_cast<const uint8*>([mac bytes]));
+ access_point_data.radio_signal_strength = [[network rssi] intValue];
+ access_point_data.channel = [[network channel] intValue];
+ access_point_data.signal_to_noise =
+ access_point_data.radio_signal_strength - [[network noise] intValue];
+ access_point_data.ssid = UTF8ToUTF16([[network ssid] UTF8String]);
+ data->insert(access_point_data);
+ }
+ return true;
+}
+
+WifiDataProviderCommon::WlanApiInterface* NewCoreWlanApi() {
+ scoped_ptr<CoreWlanApi> self(new CoreWlanApi);
+ if (self->Init())
+ return self.release();
+
+ return NULL;
+}
diff --git a/chrome/browser/geolocation/wifi_data_provider_mac.cc b/chrome/browser/geolocation/wifi_data_provider_mac.cc
index df332e1..b669e74 100644
--- a/chrome/browser/geolocation/wifi_data_provider_mac.cc
+++ b/chrome/browser/geolocation/wifi_data_provider_mac.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// 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
+// 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"
@@ -21,10 +21,12 @@ const int kDefaultPollingInterval = 120000; // 2 mins
const int kNoChangePollingInterval = 300000; // 5 mins
const int kTwoNoChangePollingInterval = 600000; // 10 mins
-class OsxWlanApi : public WifiDataProviderCommon::WlanApiInterface {
+// Provides the wifi API binding for use when running on OSX 10.5 machines using
+// the Apple80211 framework.
+class Apple80211Api : public WifiDataProviderCommon::WlanApiInterface {
public:
- OsxWlanApi();
- virtual ~OsxWlanApi();
+ Apple80211Api();
+ virtual ~Apple80211Api();
bool Init();
@@ -42,20 +44,20 @@ class OsxWlanApi : public WifiDataProviderCommon::WlanApiInterface {
WifiData wifi_data_;
};
-OsxWlanApi::OsxWlanApi()
+Apple80211Api::Apple80211Api()
: apple_80211_library_(NULL), wifi_context_(NULL),
WirelessAttach_function_(NULL), WirelessScanSplit_function_(NULL),
WirelessDetach_function_(NULL) {
}
-OsxWlanApi::~OsxWlanApi() {
+Apple80211Api::~Apple80211Api() {
if (WirelessDetach_function_)
(*WirelessDetach_function_)(wifi_context_);
dlclose(apple_80211_library_);
}
-bool OsxWlanApi::Init() {
- DLOG(INFO) << "OsxWlanApi::Init";
+bool Apple80211Api::Init() {
+ DLOG(INFO) << "Apple80211Api::Init";
apple_80211_library_ = dlopen(
"/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
RTLD_LAZY);
@@ -89,8 +91,8 @@ bool OsxWlanApi::Init() {
return true;
}
-bool OsxWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
- DLOG(INFO) << "OsxWlanApi::GetAccessPointData";
+bool Apple80211Api::GetAccessPointData(WifiData::AccessPointDataSet* data) {
+ DLOG(INFO) << "Apple80211Api::GetAccessPointData";
DCHECK(data);
DCHECK(WirelessScanSplit_function_);
CFArrayRef managed_access_points = NULL;
@@ -110,7 +112,7 @@ bool OsxWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
}
int num_access_points = CFArrayGetCount(managed_access_points);
- DLOG(INFO) << "Found " << num_access_points << " 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*>(
@@ -120,7 +122,6 @@ bool OsxWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
// 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);
@@ -135,10 +136,6 @@ bool OsxWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
&access_point_data.ssid)) {
access_point_data.ssid.clear();
}
-
- DLOG(INFO) << " AP " << i
- << " mac: " << access_point_data.mac_address
- << " ssid: " << access_point_data.ssid;
data->insert(access_point_data);
}
return true;
@@ -148,25 +145,32 @@ bool OsxWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
// static
template<>
WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
- return new OsxWifiDataProvider();
+ return new MacWifiDataProvider();
}
-OsxWifiDataProvider::OsxWifiDataProvider() {
+MacWifiDataProvider::MacWifiDataProvider() {
}
-OsxWifiDataProvider::~OsxWifiDataProvider() {
+MacWifiDataProvider::~MacWifiDataProvider() {
}
-OsxWifiDataProvider::WlanApiInterface* OsxWifiDataProvider::NewWlanApi() {
- scoped_ptr<OsxWlanApi> wlan_api(new OsxWlanApi);
- if (!wlan_api->Init()) {
- DLOG(INFO) << "OsxWifiDataProvider : failed to initialize wlan api";
- return NULL;
- }
- return wlan_api.release();
+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* OsxWifiDataProvider::NewPollingPolicy() {
+PollingPolicyInterface* MacWifiDataProvider::NewPollingPolicy() {
return new GenericPollingPolicy<kDefaultPollingInterval,
kNoChangePollingInterval,
kTwoNoChangePollingInterval>;
diff --git a/chrome/browser/geolocation/wifi_data_provider_mac.h b/chrome/browser/geolocation/wifi_data_provider_mac.h
index a386c59..841176e 100644
--- a/chrome/browser/geolocation/wifi_data_provider_mac.h
+++ b/chrome/browser/geolocation/wifi_data_provider_mac.h
@@ -7,18 +7,25 @@
#include "chrome/browser/geolocation/wifi_data_provider_common.h"
-class OsxWifiDataProvider : public WifiDataProviderCommon {
+// Implementation of the wifi data provider for Mac OSX. Uses different API
+// bindings depending on APIs detected available at runtime in order to access
+// wifi scan data: Apple80211.h on OSX 10.5, CoreWLAN framework on OSX 10.6.
+class MacWifiDataProvider : public WifiDataProviderCommon {
public:
- OsxWifiDataProvider();
+ MacWifiDataProvider();
private:
- virtual ~OsxWifiDataProvider();
+ virtual ~MacWifiDataProvider();
// WifiDataProviderCommon
virtual WlanApiInterface* NewWlanApi();
virtual PollingPolicyInterface* NewPollingPolicy();
- DISALLOW_COPY_AND_ASSIGN(OsxWifiDataProvider);
+ DISALLOW_COPY_AND_ASSIGN(MacWifiDataProvider);
};
+// Creates and returns a new API binding for the CoreWLAN API, or NULL if the
+// API can not be initialized.
+WifiDataProviderCommon::WlanApiInterface* NewCoreWlanApi();
+
#endif // CHROME_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MAC_H_