1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "chre/platform/linux/pal_wifi.h"
18
19 #include <atomic>
20 #include <chrono>
21 #include <cinttypes>
22 #include <optional>
23
24 #include "chre/pal/wifi.h"
25 #include "chre/platform/linux/pal_nan.h"
26 #include "chre/platform/linux/task_util/task_manager.h"
27 #include "chre/util/enum.h"
28 #include "chre/util/memory.h"
29 #include "chre/util/time.h"
30 #include "chre/util/unique_ptr.h"
31
32 /**
33 * A simulated implementation of the WiFi PAL for the linux platform.
34 */
35 namespace {
36
37 using ::chre::TaskManagerSingleton;
38
39 const struct chrePalSystemApi *gSystemApi = nullptr;
40 const struct chrePalWifiCallbacks *gCallbacks = nullptr;
41
42 //! Whether scan monitoring is active.
43 std::atomic_bool gScanMonitoringActive(false);
44
45 //! Whether PAL should respond to RRT ranging request.
46 std::atomic_bool gEnableRangingResponse(true);
47
48 //! Whether PAL should respond to configure scan monitor request.
49 std::atomic_bool gEnableScanMonitorResponse(true);
50
51 //! Whether PAL should respond to scan request.
52 std::atomic_bool gEnableScanResponse(true);
53
54 //! Thread sync variable for TaskIds.
55 std::mutex gRequestScanMutex;
56
57 //! Task IDs for the scanning tasks
58 std::optional<uint32_t> gScanMonitorTaskId;
59 std::optional<uint32_t> gRequestScanTaskId;
60 std::optional<uint32_t> gRequestRangingTaskId;
61
62 //! How long should each the PAL hold before response.
63 //! Use to mimic real world hardware process time.
64 std::chrono::nanoseconds gAsyncRequestDelayResponseTime[chre::asBaseType(
65 PalWifiAsyncRequestTypes::NUM_WIFI_REQUEST_TYPE)];
66
sendScanResponse()67 void sendScanResponse() {
68 {
69 std::lock_guard<std::mutex> lock(gRequestScanMutex);
70 if (!gRequestScanTaskId.has_value()) {
71 LOGE("Sending scan response with no pending task");
72 return;
73 }
74 gRequestScanTaskId.reset();
75 }
76
77 if (gEnableScanResponse) {
78 auto event = chre::MakeUniqueZeroFill<struct chreWifiScanEvent>();
79 auto result = chre::MakeUniqueZeroFill<struct chreWifiScanResult>();
80 event->resultCount = 1;
81 event->resultTotal = 1;
82 event->referenceTime = gSystemApi->getCurrentTime();
83 event->results = result.release();
84 gCallbacks->scanEventCallback(event.release());
85 }
86 }
87
sendScanMonitorResponse(bool enable)88 void sendScanMonitorResponse(bool enable) {
89 if (gEnableScanMonitorResponse) {
90 gCallbacks->scanMonitorStatusChangeCallback(enable, CHRE_ERROR_NONE);
91 }
92 }
93
sendRangingResponse()94 void sendRangingResponse() {
95 if (gEnableRangingResponse) {
96 auto event = chre::MakeUniqueZeroFill<struct chreWifiRangingEvent>();
97 auto result = chre::MakeUniqueZeroFill<struct chreWifiRangingResult>();
98 event->resultCount = 1;
99 event->results = result.release();
100 gCallbacks->rangingEventCallback(CHRE_ERROR_NONE, event.release());
101 }
102 }
103
stopScanMonitorTask()104 void stopScanMonitorTask() {
105 if (gScanMonitorTaskId.has_value()) {
106 TaskManagerSingleton::get()->cancelTask(gScanMonitorTaskId.value());
107 gScanMonitorTaskId.reset();
108 }
109 }
110
stopRequestScanTask()111 void stopRequestScanTask() {
112 if (gRequestScanTaskId.has_value()) {
113 TaskManagerSingleton::get()->cancelTask(gRequestScanTaskId.value());
114 gRequestScanTaskId.reset();
115 }
116 }
117
stopRequestRangingTask()118 void stopRequestRangingTask() {
119 if (gRequestRangingTaskId.has_value()) {
120 TaskManagerSingleton::get()->cancelTask(gRequestRangingTaskId.value());
121 gRequestRangingTaskId.reset();
122 }
123 }
124
chrePalWifiGetCapabilities()125 uint32_t chrePalWifiGetCapabilities() {
126 return CHRE_WIFI_CAPABILITIES_SCAN_MONITORING |
127 CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN | CHRE_WIFI_CAPABILITIES_NAN_SUB;
128 }
129
chrePalWifiConfigureScanMonitor(bool enable)130 bool chrePalWifiConfigureScanMonitor(bool enable) {
131 stopScanMonitorTask();
132
133 gScanMonitorTaskId = TaskManagerSingleton::get()->addTask(
134 [enable]() { sendScanMonitorResponse(enable); });
135 gScanMonitoringActive = enable;
136 return gScanMonitorTaskId.has_value();
137 }
138
chrePalWifiApiRequestScan(const struct chreWifiScanParams *)139 bool chrePalWifiApiRequestScan(const struct chreWifiScanParams * /* params */) {
140 std::lock_guard<std::mutex> lock(gRequestScanMutex);
141 if (gRequestScanTaskId.has_value()) {
142 LOGE("Requesting scan when existing scan request still in process");
143 return false;
144 }
145
146 std::optional<uint32_t> requestScanTaskCallbackId =
147 TaskManagerSingleton::get()->addTask([]() {
148 if (gEnableScanResponse) {
149 gCallbacks->scanResponseCallback(true, CHRE_ERROR_NONE);
150 }
151 });
152 if (requestScanTaskCallbackId.has_value()) {
153 gRequestScanTaskId = TaskManagerSingleton::get()->addTask(
154 sendScanResponse,
155 gAsyncRequestDelayResponseTime[chre::asBaseType(
156 PalWifiAsyncRequestTypes::SCAN)],
157 /* isOneShot= */ true);
158 return gRequestScanTaskId.has_value();
159 }
160 return false;
161 }
162
chrePalWifiApiRequestRanging(const struct chreWifiRangingParams *)163 bool chrePalWifiApiRequestRanging(
164 const struct chreWifiRangingParams * /* params */) {
165 stopRequestRangingTask();
166
167 gRequestRangingTaskId =
168 TaskManagerSingleton::get()->addTask(sendRangingResponse);
169 return gRequestRangingTaskId.has_value();
170 }
171
chrePalWifiApiReleaseScanEvent(struct chreWifiScanEvent * event)172 void chrePalWifiApiReleaseScanEvent(struct chreWifiScanEvent *event) {
173 chre::memoryFree(const_cast<uint32_t *>(event->scannedFreqList));
174 chre::memoryFree(const_cast<struct chreWifiScanResult *>(event->results));
175 chre::memoryFree(event);
176 }
177
chrePalWifiApiReleaseRangingEvent(struct chreWifiRangingEvent * event)178 void chrePalWifiApiReleaseRangingEvent(struct chreWifiRangingEvent *event) {
179 chre::memoryFree(const_cast<struct chreWifiRangingResult *>(event->results));
180 chre::memoryFree(event);
181 }
182
chrePalWifiApiNanSubscribe(const struct chreWifiNanSubscribeConfig * config)183 bool chrePalWifiApiNanSubscribe(
184 const struct chreWifiNanSubscribeConfig *config) {
185 uint32_t subscriptionId = 0;
186 uint8_t errorCode =
187 chre::PalNanEngineSingleton::get()->subscribe(config, &subscriptionId);
188
189 gCallbacks->nanServiceIdentifierCallback(errorCode, subscriptionId);
190
191 return true;
192 }
193
chrePalWifiApiNanSubscribeCancel(const uint32_t subscriptionId)194 bool chrePalWifiApiNanSubscribeCancel(const uint32_t subscriptionId) {
195 gCallbacks->nanSubscriptionCanceledCallback(CHRE_ERROR_NONE, subscriptionId);
196 return chre::PalNanEngineSingleton::get()->subscribeCancel(subscriptionId);
197 }
198
chrePalWifiApiNanReleaseDiscoveryEvent(struct chreWifiNanDiscoveryEvent * event)199 void chrePalWifiApiNanReleaseDiscoveryEvent(
200 struct chreWifiNanDiscoveryEvent *event) {
201 chre::PalNanEngineSingleton::get()->destroyDiscoveryEvent(event);
202 }
203
chrePalWifiApiRequestNanRanging(const struct chreWifiNanRangingParams * params)204 bool chrePalWifiApiRequestNanRanging(
205 const struct chreWifiNanRangingParams *params) {
206 constexpr uint32_t kFakeRangeMeasurementMm = 1000;
207
208 auto *event = chre::memoryAlloc<struct chreWifiRangingEvent>();
209 CHRE_ASSERT_NOT_NULL(event);
210
211 auto *result = chre::memoryAlloc<struct chreWifiRangingResult>();
212 CHRE_ASSERT_NOT_NULL(result);
213
214 std::memcpy(result->macAddress, params->macAddress, CHRE_WIFI_BSSID_LEN);
215 result->status = CHRE_WIFI_RANGING_STATUS_SUCCESS;
216 result->distance = kFakeRangeMeasurementMm;
217 event->resultCount = 1;
218 event->results = result;
219
220 gCallbacks->rangingEventCallback(CHRE_ERROR_NONE, event);
221
222 return true;
223 }
224
chrePalWifiApiClose()225 void chrePalWifiApiClose() {
226 stopScanMonitorTask();
227 stopRequestScanTask();
228 stopRequestRangingTask();
229 }
230
chrePalWifiApiOpen(const struct chrePalSystemApi * systemApi,const struct chrePalWifiCallbacks * callbacks)231 bool chrePalWifiApiOpen(const struct chrePalSystemApi *systemApi,
232 const struct chrePalWifiCallbacks *callbacks) {
233 chrePalWifiApiClose();
234
235 bool success = false;
236 if (systemApi != nullptr && callbacks != nullptr) {
237 gSystemApi = systemApi;
238 gCallbacks = callbacks;
239
240 chre::PalNanEngineSingleton::get()->setPlatformWifiCallbacks(callbacks);
241
242 success = true;
243 }
244
245 return success;
246 }
247
chrePalWifiNanGetCapabilities(struct chreWifiNanCapabilities *)248 bool chrePalWifiNanGetCapabilities(
249 struct chreWifiNanCapabilities * /* capabilities */) {
250 return false;
251 }
252
253 } // anonymous namespace
254
chrePalWifiEnableResponse(PalWifiAsyncRequestTypes requestType,bool enableResponse)255 void chrePalWifiEnableResponse(PalWifiAsyncRequestTypes requestType,
256 bool enableResponse) {
257 switch (requestType) {
258 case PalWifiAsyncRequestTypes::RANGING:
259 gEnableRangingResponse = enableResponse;
260 break;
261
262 case PalWifiAsyncRequestTypes::SCAN_MONITORING:
263 gEnableScanMonitorResponse = enableResponse;
264 break;
265
266 case PalWifiAsyncRequestTypes::SCAN:
267 gEnableScanResponse = enableResponse;
268 break;
269
270 default:
271 LOGE("Cannot enable/disable request type: %" PRIu8,
272 static_cast<uint8_t>(requestType));
273 }
274 }
275
chrePalWifiIsScanMonitoringActive()276 bool chrePalWifiIsScanMonitoringActive() {
277 return gScanMonitoringActive;
278 }
279
chrePalWifiDelayResponse(PalWifiAsyncRequestTypes requestType,std::chrono::milliseconds milliseconds)280 void chrePalWifiDelayResponse(PalWifiAsyncRequestTypes requestType,
281 std::chrono::milliseconds milliseconds) {
282 gAsyncRequestDelayResponseTime[chre::asBaseType(requestType)] =
283 std::chrono::duration_cast<std::chrono::nanoseconds>(milliseconds);
284 ;
285 }
286
chrePalWifiGetApi(uint32_t requestedApiVersion)287 const struct chrePalWifiApi *chrePalWifiGetApi(uint32_t requestedApiVersion) {
288 static const struct chrePalWifiApi kApi = {
289 .moduleVersion = CHRE_PAL_WIFI_API_CURRENT_VERSION,
290 .open = chrePalWifiApiOpen,
291 .close = chrePalWifiApiClose,
292 .getCapabilities = chrePalWifiGetCapabilities,
293 .configureScanMonitor = chrePalWifiConfigureScanMonitor,
294 .requestScan = chrePalWifiApiRequestScan,
295 .releaseScanEvent = chrePalWifiApiReleaseScanEvent,
296 .requestRanging = chrePalWifiApiRequestRanging,
297 .releaseRangingEvent = chrePalWifiApiReleaseRangingEvent,
298 .nanSubscribe = chrePalWifiApiNanSubscribe,
299 .nanSubscribeCancel = chrePalWifiApiNanSubscribeCancel,
300 .releaseNanDiscoveryEvent = chrePalWifiApiNanReleaseDiscoveryEvent,
301 .requestNanRanging = chrePalWifiApiRequestNanRanging,
302 .getNanCapabilities = chrePalWifiNanGetCapabilities,
303 };
304
305 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
306 requestedApiVersion)) {
307 return nullptr;
308 } else {
309 chre::PalNanEngineSingleton::init();
310 return &kApi;
311 }
312 }
313