Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / geolocation / wifi_data_provider_mac.cc
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.
4
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).
9
10 #include "content/browser/geolocation/wifi_data_provider_mac.h"
11
12 #include <dlfcn.h>
13 #include <stdio.h>
14
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"
19
20 namespace content {
21 namespace {
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
27
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 {
31  public:
32   Apple80211Api();
33   ~Apple80211Api() override;
34
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.
38   bool Init();
39
40   // WlanApiInterface
41   bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
42
43  private:
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_;
50
51   WifiData wifi_data_;
52
53   DISALLOW_COPY_AND_ASSIGN(Apple80211Api);
54 };
55
56 Apple80211Api::Apple80211Api()
57     : apple_80211_library_(NULL), wifi_context_(NULL),
58       WirelessAttach_function_(NULL), WirelessScanSplit_function_(NULL),
59       WirelessDetach_function_(NULL) {
60 }
61
62 Apple80211Api::~Apple80211Api() {
63   if (WirelessDetach_function_)
64     (*WirelessDetach_function_)(wifi_context_);
65   dlclose(apple_80211_library_);
66 }
67
68 bool Apple80211Api::Init() {
69   DVLOG(1) << "Apple80211Api::Init";
70   apple_80211_library_ = dlopen(
71       "/System/Library/PrivateFrameworks/Apple80211.framework/Apple80211",
72       RTLD_LAZY);
73   if (!apple_80211_library_) {
74     DLOG(WARNING) << "Could not open Apple80211 library";
75     return false;
76   }
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_);
86
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_;
92     return false;
93   }
94
95   WIErr err = (*WirelessAttach_function_)(&wifi_context_, 0);
96   if (err != noErr) {
97     DLOG(WARNING) << "Error attaching: " << err;
98     return false;
99   }
100   return true;
101 }
102
103 bool Apple80211Api::GetAccessPointData(WifiData::AccessPointDataSet* data) {
104   DVLOG(1) << "Apple80211Api::GetAccessPointData";
105   DCHECK(data);
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,
113                                              0);
114   if (err != noErr) {
115     DLOG(WARNING) << "Error spliting scan: " << err;
116     return false;
117   }
118
119   if (managed_access_points == NULL) {
120     DLOG(WARNING) << "managed_access_points == NULL";
121     return false;
122   }
123
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*>(
129         CFDataGetBytePtr(
130         reinterpret_cast<const CFDataRef>(
131         CFArrayGetValueAtIndex(managed_access_points, i))));
132
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();
149     }
150     data->insert(access_point_data);
151   }
152
153   if (managed_access_points)
154     CFRelease(managed_access_points);
155   if (adhoc_access_points)
156     CFRelease(adhoc_access_points);
157
158   return true;
159 }
160 }  // namespace
161
162 // static
163 WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
164   return new WifiDataProviderMac();
165 }
166
167 WifiDataProviderMac::WifiDataProviderMac() {
168 }
169
170 WifiDataProviderMac::~WifiDataProviderMac() {
171 }
172
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();
178   if (core_wlan_api)
179     return core_wlan_api;
180
181   scoped_ptr<Apple80211Api> wlan_api(new Apple80211Api);
182   if (wlan_api->Init())
183     return wlan_api.release();
184
185   DVLOG(1) << "WifiDataProviderMac : failed to initialize any wlan api";
186   return NULL;
187 }
188
189 WifiPollingPolicy* WifiDataProviderMac::NewPollingPolicy() {
190   return new GenericWifiPollingPolicy<kDefaultPollingInterval,
191                                       kNoChangePollingInterval,
192                                       kTwoNoChangePollingInterval,
193                                       kNoWifiPollingIntervalMilliseconds>;
194 }
195
196 }  // namespace content