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/pal/wifi.h"
18
19 #include "chre/util/memory.h"
20 #include "chre/util/unique_ptr.h"
21
22 #include "chre/platform/linux/pal_nan.h"
23
24 #include <chrono>
25 #include <cinttypes>
26 #include <thread>
27
28 /**
29 * A simulated implementation of the WiFi PAL for the linux platform.
30 */
31 namespace {
32 const struct chrePalSystemApi *gSystemApi = nullptr;
33 const struct chrePalWifiCallbacks *gCallbacks = nullptr;
34
35 //! Thread to deliver asynchronous WiFi scan results after a CHRE request.
36 std::thread gScanEventsThread;
37
38 //! Thread to use when delivering a scan monitor status update.
39 std::thread gScanMonitorStatusThread;
40
41 //! Whether scan monitoring is active.
42 bool gScanMonitoringActive = false;
43
sendScanResponse()44 void sendScanResponse() {
45 gCallbacks->scanResponseCallback(true, CHRE_ERROR_NONE);
46
47 auto event = chre::MakeUniqueZeroFill<struct chreWifiScanEvent>();
48 auto result = chre::MakeUniqueZeroFill<struct chreWifiScanResult>();
49 event->resultCount = 1;
50 event->resultTotal = 1;
51 event->referenceTime = gSystemApi->getCurrentTime();
52 event->results = result.release();
53
54 gCallbacks->scanEventCallback(event.release());
55 }
56
sendScanMonitorResponse(bool enable)57 void sendScanMonitorResponse(bool enable) {
58 gCallbacks->scanMonitorStatusChangeCallback(enable, CHRE_ERROR_NONE);
59 }
60
stopScanEventThreads()61 void stopScanEventThreads() {
62 if (gScanEventsThread.joinable()) {
63 gScanEventsThread.join();
64 }
65 }
66
stopScanMonitorThreads()67 void stopScanMonitorThreads() {
68 if (gScanMonitorStatusThread.joinable()) {
69 gScanMonitorStatusThread.join();
70 }
71 }
72
chrePalWifiGetCapabilities()73 uint32_t chrePalWifiGetCapabilities() {
74 return CHRE_WIFI_CAPABILITIES_SCAN_MONITORING |
75 CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN | CHRE_WIFI_CAPABILITIES_NAN_SUB;
76 }
77
chrePalWifiConfigureScanMonitor(bool enable)78 bool chrePalWifiConfigureScanMonitor(bool enable) {
79 stopScanMonitorThreads();
80
81 gScanMonitorStatusThread = std::thread(sendScanMonitorResponse, enable);
82 gScanMonitoringActive = enable;
83
84 return true;
85 }
86
chrePalWifiApiRequestScan(const struct chreWifiScanParams *)87 bool chrePalWifiApiRequestScan(const struct chreWifiScanParams * /* params */) {
88 stopScanEventThreads();
89
90 gScanEventsThread = std::thread(sendScanResponse);
91
92 return true;
93 }
94
chrePalWifiApiRequestRanging(const struct chreWifiRangingParams *)95 bool chrePalWifiApiRequestRanging(
96 const struct chreWifiRangingParams * /* params */) {
97 // unimplemented
98 return false;
99 }
100
chrePalWifiApiReleaseScanEvent(struct chreWifiScanEvent * event)101 void chrePalWifiApiReleaseScanEvent(struct chreWifiScanEvent *event) {
102 chre::memoryFree(const_cast<uint32_t *>(event->scannedFreqList));
103 chre::memoryFree(const_cast<struct chreWifiScanResult *>(event->results));
104 chre::memoryFree(event);
105 }
106
chrePalWifiApiReleaseRangingEvent(struct chreWifiRangingEvent * event)107 void chrePalWifiApiReleaseRangingEvent(struct chreWifiRangingEvent *event) {
108 chre::memoryFree(const_cast<struct chreWifiRangingResult *>(event->results));
109 chre::memoryFree(event);
110 }
111
chrePalWifiApiNanSubscribe(const struct chreWifiNanSubscribeConfig * config)112 bool chrePalWifiApiNanSubscribe(
113 const struct chreWifiNanSubscribeConfig *config) {
114 uint32_t subscriptionId = 0;
115 uint8_t errorCode =
116 chre::PalNanEngineSingleton::get()->subscribe(config, &subscriptionId);
117
118 gCallbacks->nanServiceIdentifierCallback(errorCode, subscriptionId);
119
120 return true;
121 }
122
chrePalWifiApiNanSubscribeCancel(const uint32_t subscriptionId)123 bool chrePalWifiApiNanSubscribeCancel(const uint32_t subscriptionId) {
124 gCallbacks->nanSubscriptionCanceledCallback(CHRE_ERROR_NONE, subscriptionId);
125 return chre::PalNanEngineSingleton::get()->subscribeCancel(subscriptionId);
126 }
127
chrePalWifiApiNanReleaseDiscoveryEvent(struct chreWifiNanDiscoveryEvent * event)128 void chrePalWifiApiNanReleaseDiscoveryEvent(
129 struct chreWifiNanDiscoveryEvent *event) {
130 chre::PalNanEngineSingleton::get()->destroyDiscoveryEvent(event);
131 }
132
chrePalWifiApiRequestNanRanging(const struct chreWifiNanRangingParams * params)133 bool chrePalWifiApiRequestNanRanging(
134 const struct chreWifiNanRangingParams *params) {
135 constexpr uint32_t kFakeRangeMeasurementMm = 1000;
136
137 auto *event = chre::memoryAlloc<struct chreWifiRangingEvent>();
138 CHRE_ASSERT_NOT_NULL(event);
139
140 auto *result = chre::memoryAlloc<struct chreWifiRangingResult>();
141 CHRE_ASSERT_NOT_NULL(result);
142
143 std::memcpy(result->macAddress, params->macAddress, CHRE_WIFI_BSSID_LEN);
144 result->status = CHRE_WIFI_RANGING_STATUS_SUCCESS;
145 result->distance = kFakeRangeMeasurementMm;
146 event->resultCount = 1;
147 event->results = result;
148
149 gCallbacks->rangingEventCallback(CHRE_ERROR_NONE, event);
150
151 return true;
152 }
153
chrePalWifiApiClose()154 void chrePalWifiApiClose() {
155 stopScanEventThreads();
156 stopScanMonitorThreads();
157 }
158
chrePalWifiApiOpen(const struct chrePalSystemApi * systemApi,const struct chrePalWifiCallbacks * callbacks)159 bool chrePalWifiApiOpen(const struct chrePalSystemApi *systemApi,
160 const struct chrePalWifiCallbacks *callbacks) {
161 chrePalWifiApiClose();
162
163 bool success = false;
164 if (systemApi != nullptr && callbacks != nullptr) {
165 gSystemApi = systemApi;
166 gCallbacks = callbacks;
167
168 chre::PalNanEngineSingleton::get()->setPlatformWifiCallbacks(callbacks);
169
170 success = true;
171 }
172
173 return success;
174 }
175
176 } // anonymous namespace
177
chrePalWifiIsScanMonitoringActive()178 bool chrePalWifiIsScanMonitoringActive() {
179 return gScanMonitoringActive;
180 }
181
chrePalWifiGetApi(uint32_t requestedApiVersion)182 const struct chrePalWifiApi *chrePalWifiGetApi(uint32_t requestedApiVersion) {
183 static const struct chrePalWifiApi kApi = {
184 .moduleVersion = CHRE_PAL_WIFI_API_CURRENT_VERSION,
185 .open = chrePalWifiApiOpen,
186 .close = chrePalWifiApiClose,
187 .getCapabilities = chrePalWifiGetCapabilities,
188 .configureScanMonitor = chrePalWifiConfigureScanMonitor,
189 .requestScan = chrePalWifiApiRequestScan,
190 .releaseScanEvent = chrePalWifiApiReleaseScanEvent,
191 .requestRanging = chrePalWifiApiRequestRanging,
192 .releaseRangingEvent = chrePalWifiApiReleaseRangingEvent,
193 .nanSubscribe = chrePalWifiApiNanSubscribe,
194 .nanSubscribeCancel = chrePalWifiApiNanSubscribeCancel,
195 .releaseNanDiscoveryEvent = chrePalWifiApiNanReleaseDiscoveryEvent,
196 .requestNanRanging = chrePalWifiApiRequestNanRanging,
197 };
198
199 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(kApi.moduleVersion,
200 requestedApiVersion)) {
201 return nullptr;
202 } else {
203 chre::PalNanEngineSingleton::init();
204 return &kApi;
205 }
206 }
207