1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
// 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 "content/browser/geolocation/wifi_data_provider_mac.h"
#include <dlfcn.h>
#include <stdio.h>
#include "base/strings/utf_string_conversions.h"
#include "content/browser/geolocation/osx_wifi.h"
#include "content/browser/geolocation/wifi_data_provider_common.h"
#include "content/browser/geolocation/wifi_data_provider_manager.h"
namespace content {
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();
~Apple80211Api() override;
// 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
bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
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() {
DVLOG(1) << "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) {
DVLOG(1) << "Apple80211Api::GetAccessPointData";
DCHECK(data);
DCHECK(WirelessScanSplit_function_);
CFArrayRef managed_access_points = NULL;
CFArrayRef adhoc_access_points = NULL;
// Arrays returned here are owned by the caller.
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);
DVLOG(1) << "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 (!base::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);
}
if (managed_access_points)
CFRelease(managed_access_points);
if (adhoc_access_points)
CFRelease(adhoc_access_points);
return true;
}
} // namespace
// static
WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
return new WifiDataProviderMac();
}
WifiDataProviderMac::WifiDataProviderMac() {
}
WifiDataProviderMac::~WifiDataProviderMac() {
}
WifiDataProviderMac::WlanApiInterface* WifiDataProviderMac::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.
WifiDataProviderMac::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();
DVLOG(1) << "WifiDataProviderMac : failed to initialize any wlan api";
return NULL;
}
WifiPollingPolicy* WifiDataProviderMac::NewPollingPolicy() {
return new GenericWifiPollingPolicy<kDefaultPollingInterval,
kNoChangePollingInterval,
kTwoNoChangePollingInterval,
kNoWifiPollingIntervalMilliseconds>;
}
} // namespace content
|