1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // For OSX 10.5 we use the system API function WirelessScanSplit. This function
6 // is not documented or included in the SDK, so we use a reverse-engineered
7 // header, osx_wifi_.h. This file is taken from the iStumbler project
8 // (http://www.istumbler.net).
10 #include "content/browser/geolocation/wifi_data_provider_mac.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "content/browser/geolocation/osx_wifi.h"
17 #include "content/browser/geolocation/wifi_data_provider_common.h"
18 #include "content/browser/geolocation/wifi_data_provider_manager.h"
22 // The time periods, in milliseconds, between successive polls of the wifi data.
23 const int kDefaultPollingInterval
= 120000; // 2 mins
24 const int kNoChangePollingInterval
= 300000; // 5 mins
25 const int kTwoNoChangePollingInterval
= 600000; // 10 mins
26 const int kNoWifiPollingIntervalMilliseconds
= 20 * 1000; // 20s
28 // Provides the wifi API binding for use when running on OSX 10.5 machines using
29 // the Apple80211 framework.
30 class Apple80211Api
: public WifiDataProviderCommon::WlanApiInterface
{
33 ~Apple80211Api() override
;
35 // Must be called before any other interface method. Will return false if the
36 // Apple80211 framework cannot be initialized (e.g. running on post-10.5 OSX),
37 // in which case no other method may be called.
41 bool GetAccessPointData(WifiData::AccessPointDataSet
* data
) override
;
44 // Handle, context and function pointers for Apple80211 library.
45 void* apple_80211_library_
;
46 WirelessContext
* wifi_context_
;
47 WirelessAttachFunction WirelessAttach_function_
;
48 WirelessScanSplitFunction WirelessScanSplit_function_
;
49 WirelessDetachFunction WirelessDetach_function_
;
53 DISALLOW_COPY_AND_ASSIGN(Apple80211Api
);
56 Apple80211Api::Apple80211Api()
57 : apple_80211_library_(NULL
), wifi_context_(NULL
),
58 WirelessAttach_function_(NULL
), WirelessScanSplit_function_(NULL
),
59 WirelessDetach_function_(NULL
) {
62 Apple80211Api::~Apple80211Api() {
63 if (WirelessDetach_function_
)
64 (*WirelessDetach_function_
)(wifi_context_
);
65 dlclose(apple_80211_library_
);
68 bool Apple80211Api::Init() {
69 DVLOG(1) << "Apple80211Api::Init";
70 apple_80211_library_
= dlopen(
71 "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
73 if (!apple_80211_library_
) {
74 DLOG(WARNING
) << "Could not open Apple80211 library";
77 WirelessAttach_function_
= reinterpret_cast<WirelessAttachFunction
>(
78 dlsym(apple_80211_library_
, "WirelessAttach"));
79 WirelessScanSplit_function_
= reinterpret_cast<WirelessScanSplitFunction
>(
80 dlsym(apple_80211_library_
, "WirelessScanSplit"));
81 WirelessDetach_function_
= reinterpret_cast<WirelessDetachFunction
>(
82 dlsym(apple_80211_library_
, "WirelessDetach"));
83 DCHECK(WirelessAttach_function_
);
84 DCHECK(WirelessScanSplit_function_
);
85 DCHECK(WirelessDetach_function_
);
87 if (!WirelessAttach_function_
|| !WirelessScanSplit_function_
||
88 !WirelessDetach_function_
) {
89 DLOG(WARNING
) << "Symbol error. Attach: " << !!WirelessAttach_function_
90 << " Split: " << !!WirelessScanSplit_function_
91 << " Detach: " << !!WirelessDetach_function_
;
95 WIErr err
= (*WirelessAttach_function_
)(&wifi_context_
, 0);
97 DLOG(WARNING
) << "Error attaching: " << err
;
103 bool Apple80211Api::GetAccessPointData(WifiData::AccessPointDataSet
* data
) {
104 DVLOG(1) << "Apple80211Api::GetAccessPointData";
106 DCHECK(WirelessScanSplit_function_
);
107 CFArrayRef managed_access_points
= NULL
;
108 CFArrayRef adhoc_access_points
= NULL
;
109 // Arrays returned here are owned by the caller.
110 WIErr err
= (*WirelessScanSplit_function_
)(wifi_context_
,
111 &managed_access_points
,
112 &adhoc_access_points
,
115 DLOG(WARNING
) << "Error spliting scan: " << err
;
119 if (managed_access_points
== NULL
) {
120 DLOG(WARNING
) << "managed_access_points == NULL";
124 int num_access_points
= CFArrayGetCount(managed_access_points
);
125 DVLOG(1) << "Found " << num_access_points
<< " managed access points";
126 for (int i
= 0; i
< num_access_points
; ++i
) {
127 const WirelessNetworkInfo
* access_point_info
=
128 reinterpret_cast<const WirelessNetworkInfo
*>(
130 reinterpret_cast<const CFDataRef
>(
131 CFArrayGetValueAtIndex(managed_access_points
, i
))));
133 // Currently we get only MAC address, signal strength, channel
134 // signal-to-noise and SSID
135 AccessPointData access_point_data
;
136 access_point_data
.mac_address
=
137 MacAddressAsString16(access_point_info
->macAddress
);
138 // WirelessNetworkInfo::signal appears to be signal strength in dBm.
139 access_point_data
.radio_signal_strength
= access_point_info
->signal
;
140 access_point_data
.channel
= access_point_info
->channel
;
141 // WirelessNetworkInfo::noise appears to be noise floor in dBm.
142 access_point_data
.signal_to_noise
= access_point_info
->signal
-
143 access_point_info
->noise
;
144 if (!base::UTF8ToUTF16(reinterpret_cast<const char*>(
145 access_point_info
->name
),
146 access_point_info
->nameLen
,
147 &access_point_data
.ssid
)) {
148 access_point_data
.ssid
.clear();
150 data
->insert(access_point_data
);
153 if (managed_access_points
)
154 CFRelease(managed_access_points
);
155 if (adhoc_access_points
)
156 CFRelease(adhoc_access_points
);
163 WifiDataProvider
* WifiDataProviderManager::DefaultFactoryFunction() {
164 return new WifiDataProviderMac();
167 WifiDataProviderMac::WifiDataProviderMac() {
170 WifiDataProviderMac::~WifiDataProviderMac() {
173 WifiDataProviderMac::WlanApiInterface
* WifiDataProviderMac::NewWlanApi() {
174 // Try and find a API binding that works: first try the officially supported
175 // CoreWLAN API, and if this fails (e.g. on OSX 10.5) fall back to the reverse
176 // engineered Apple80211 API.
177 WifiDataProviderMac::WlanApiInterface
* core_wlan_api
= NewCoreWlanApi();
179 return core_wlan_api
;
181 scoped_ptr
<Apple80211Api
> wlan_api(new Apple80211Api
);
182 if (wlan_api
->Init())
183 return wlan_api
.release();
185 DVLOG(1) << "WifiDataProviderMac : failed to initialize any wlan api";
189 WifiPollingPolicy
* WifiDataProviderMac::NewPollingPolicy() {
190 return new GenericWifiPollingPolicy
<kDefaultPollingInterval
,
191 kNoChangePollingInterval
,
192 kTwoNoChangePollingInterval
,
193 kNoWifiPollingIntervalMilliseconds
>;
196 } // namespace content