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 "chpp/clients/wifi.h"
18
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <string.h>
24
25 #include "chpp/app.h"
26 #include "chpp/clients.h"
27 #include "chpp/clients/discovery.h"
28 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
29 #include "chpp/clients/timesync.h"
30 #endif
31 #include "chpp/common/standard_uuids.h"
32 #include "chpp/common/wifi.h"
33 #include "chpp/common/wifi_types.h"
34 #include "chpp/common/wifi_utils.h"
35 #include "chpp/log.h"
36 #include "chpp/macros.h"
37 #include "chpp/memory.h"
38 #include "chre/pal/wifi.h"
39 #include "chre_api/chre/wifi.h"
40
41 #ifndef CHPP_WIFI_DISCOVERY_TIMEOUT_MS
42 #define CHPP_WIFI_DISCOVERY_TIMEOUT_MS CHPP_DISCOVERY_DEFAULT_TIMEOUT_MS
43 #endif
44
45 #ifndef CHPP_WIFI_MAX_TIMESYNC_AGE_NS
46 #define CHPP_WIFI_MAX_TIMESYNC_AGE_NS CHPP_TIMESYNC_DEFAULT_MAX_AGE_NS
47 #endif
48
49 /************************************************
50 * Prototypes
51 ***********************************************/
52
53 static enum ChppAppErrorCode chppDispatchWifiResponse(void *clientContext,
54 uint8_t *buf, size_t len);
55 static enum ChppAppErrorCode chppDispatchWifiNotification(void *clientContext,
56 uint8_t *buf,
57 size_t len);
58 static bool chppWifiClientInit(void *clientContext, uint8_t handle,
59 struct ChppVersion serviceVersion);
60 static void chppWifiClientDeinit(void *clientContext);
61 static void chppWifiClientNotifyReset(void *clientContext);
62 static void chppWifiClientNotifyMatch(void *clientContext);
63
64 /************************************************
65 * Private Definitions
66 ***********************************************/
67
68 /**
69 * Structure to maintain state for the WiFi client and its Request/Response
70 * (RR) functionality.
71 */
72 struct ChppWifiClientState {
73 struct ChppClientState client; // WiFi client state
74 const struct chrePalWifiApi *api; // WiFi PAL API
75
76 struct ChppRequestResponseState rRState[CHPP_WIFI_CLIENT_REQUEST_MAX + 1];
77
78 uint32_t capabilities; // Cached GetCapabilities result
79 bool scanMonitorEnabled; // Scan monitoring is enabled
80 bool scanMonitorSilenceCallback; // Silence callback during recovery from a
81 // service reset
82 };
83
84 // Note: This global definition of gWifiClientContext supports only one
85 // instance of the CHPP WiFi client at a time.
86 struct ChppWifiClientState gWifiClientContext;
87 static const struct chrePalSystemApi *gSystemApi;
88 static const struct chrePalWifiCallbacks *gCallbacks;
89
90 /**
91 * Configuration parameters for this client
92 */
93 static const struct ChppClient kWifiClientConfig = {
94 .descriptor.uuid = CHPP_UUID_WIFI_STANDARD,
95
96 // Version
97 .descriptor.version.major = 1,
98 .descriptor.version.minor = 0,
99 .descriptor.version.patch = 0,
100
101 // Notifies client if CHPP is reset
102 .resetNotifierFunctionPtr = &chppWifiClientNotifyReset,
103
104 // Notifies client if they are matched to a service
105 .matchNotifierFunctionPtr = &chppWifiClientNotifyMatch,
106
107 // Service response dispatch function pointer
108 .responseDispatchFunctionPtr = &chppDispatchWifiResponse,
109
110 // Service notification dispatch function pointer
111 .notificationDispatchFunctionPtr = &chppDispatchWifiNotification,
112
113 // Service response dispatch function pointer
114 .initFunctionPtr = &chppWifiClientInit,
115
116 // Service notification dispatch function pointer
117 .deinitFunctionPtr = &chppWifiClientDeinit,
118
119 // Number of request-response states in the rRStates array.
120 .rRStateCount = ARRAY_SIZE(gWifiClientContext.rRState),
121
122 // Min length is the entire header
123 .minLength = sizeof(struct ChppAppHeader),
124 };
125
126 /************************************************
127 * Prototypes
128 ***********************************************/
129
130 static bool chppWifiClientOpen(const struct chrePalSystemApi *systemApi,
131 const struct chrePalWifiCallbacks *callbacks);
132 static void chppWifiClientClose(void);
133 static uint32_t chppWifiClientGetCapabilities(void);
134 static bool chppWifiClientConfigureScanMonitor(bool enable);
135 static bool chppWifiClientRequestScan(const struct chreWifiScanParams *params);
136 static void chppWifiClientReleaseScanEvent(struct chreWifiScanEvent *event);
137 static bool chppWifiClientRequestRanging(
138 const struct chreWifiRangingParams *params);
139 static void chppWifiClientReleaseRangingEvent(
140 struct chreWifiRangingEvent *event);
141
142 static void chppWiFiRecoverScanMonitor(
143 struct ChppWifiClientState *clientContext);
144 static void chppWifiCloseResult(struct ChppWifiClientState *clientContext,
145 uint8_t *buf, size_t len);
146 static void chppWifiGetCapabilitiesResult(
147 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len);
148 static void chppWifiConfigureScanMonitorResult(
149 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len);
150 static void chppWifiRequestScanResult(struct ChppWifiClientState *clientContext,
151 uint8_t *buf, size_t len);
152 static void chppWifiRequestRangingResult(
153 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len);
154
155 static void chppWifiScanEventNotification(
156 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len);
157 static void chppWifiRangingEventNotification(
158 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len);
159
160 /************************************************
161 * Private Functions
162 ***********************************************/
163
164 /**
165 * Dispatches a service response from the transport layer that is determined to
166 * be for the WiFi client.
167 *
168 * This function is called from the app layer using its function pointer given
169 * during client registration.
170 *
171 * @param clientContext Maintains status for each client instance.
172 * @param buf Input data. Cannot be null.
173 * @param len Length of input data in bytes.
174 *
175 * @return Indicates the result of this function call.
176 */
chppDispatchWifiResponse(void * clientContext,uint8_t * buf,size_t len)177 static enum ChppAppErrorCode chppDispatchWifiResponse(void *clientContext,
178 uint8_t *buf,
179 size_t len) {
180 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
181 struct ChppWifiClientState *wifiClientContext =
182 (struct ChppWifiClientState *)clientContext;
183 enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
184
185 if (rxHeader->command > CHPP_WIFI_CLIENT_REQUEST_MAX) {
186 error = CHPP_APP_ERROR_INVALID_COMMAND;
187
188 } else if (!chppClientTimestampResponse(
189 &wifiClientContext->client,
190 &wifiClientContext->rRState[rxHeader->command], rxHeader)) {
191 error = CHPP_APP_ERROR_UNEXPECTED_RESPONSE;
192
193 } else {
194 switch (rxHeader->command) {
195 case CHPP_WIFI_OPEN: {
196 chppClientProcessOpenResponse(&wifiClientContext->client, buf, len);
197 chppWiFiRecoverScanMonitor(wifiClientContext);
198 break;
199 }
200
201 case CHPP_WIFI_CLOSE: {
202 chppWifiCloseResult(wifiClientContext, buf, len);
203 break;
204 }
205
206 case CHPP_WIFI_GET_CAPABILITIES: {
207 chppWifiGetCapabilitiesResult(wifiClientContext, buf, len);
208 break;
209 }
210
211 case CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC: {
212 chppWifiConfigureScanMonitorResult(wifiClientContext, buf, len);
213 break;
214 }
215
216 case CHPP_WIFI_REQUEST_SCAN_ASYNC: {
217 chppWifiRequestScanResult(wifiClientContext, buf, len);
218 break;
219 }
220
221 case CHPP_WIFI_REQUEST_RANGING_ASYNC: {
222 chppWifiRequestRangingResult(wifiClientContext, buf, len);
223 break;
224 }
225
226 default: {
227 error = CHPP_APP_ERROR_INVALID_COMMAND;
228 break;
229 }
230 }
231 }
232
233 return error;
234 }
235
236 /**
237 * Dispatches a service notification from the transport layer that is determined
238 * to be for the WiFi client.
239 *
240 * This function is called from the app layer using its function pointer given
241 * during client registration.
242 *
243 * @param clientContext Maintains status for each client instance.
244 * @param buf Input data. Cannot be null.
245 * @param len Length of input data in bytes.
246 *
247 * @return Indicates the result of this function call.
248 */
chppDispatchWifiNotification(void * clientContext,uint8_t * buf,size_t len)249 static enum ChppAppErrorCode chppDispatchWifiNotification(void *clientContext,
250 uint8_t *buf,
251 size_t len) {
252 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
253 struct ChppWifiClientState *wifiClientContext =
254 (struct ChppWifiClientState *)clientContext;
255 enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
256
257 switch (rxHeader->command) {
258 case CHPP_WIFI_REQUEST_SCAN_ASYNC: {
259 chppWifiScanEventNotification(wifiClientContext, buf, len);
260 break;
261 }
262
263 case CHPP_WIFI_REQUEST_RANGING_ASYNC: {
264 chppWifiRangingEventNotification(wifiClientContext, buf, len);
265 break;
266 }
267
268 default: {
269 error = CHPP_APP_ERROR_INVALID_COMMAND;
270 break;
271 }
272 }
273
274 return error;
275 }
276
277 /**
278 * Initializes the client and provides its handle number and the version of the
279 * matched service when/if it the client is matched with a service during
280 * discovery.
281 *
282 * @param clientContext Maintains status for each client instance.
283 * @param handle Handle number for this client.
284 * @param serviceVersion Version of the matched service.
285 *
286 * @return True if client is compatible and successfully initialized.
287 */
chppWifiClientInit(void * clientContext,uint8_t handle,struct ChppVersion serviceVersion)288 static bool chppWifiClientInit(void *clientContext, uint8_t handle,
289 struct ChppVersion serviceVersion) {
290 UNUSED_VAR(serviceVersion);
291
292 struct ChppWifiClientState *wifiClientContext =
293 (struct ChppWifiClientState *)clientContext;
294 chppClientInit(&wifiClientContext->client, handle);
295
296 return true;
297 }
298
299 /**
300 * Deinitializes the client.
301 *
302 * @param clientContext Maintains status for each client instance.
303 */
chppWifiClientDeinit(void * clientContext)304 static void chppWifiClientDeinit(void *clientContext) {
305 struct ChppWifiClientState *wifiClientContext =
306 (struct ChppWifiClientState *)clientContext;
307 chppClientDeinit(&wifiClientContext->client);
308 }
309
310 /**
311 * Notifies the client of an incoming reset.
312 *
313 * @param clientContext Maintains status for each client instance.
314 */
chppWifiClientNotifyReset(void * clientContext)315 static void chppWifiClientNotifyReset(void *clientContext) {
316 struct ChppWifiClientState *wifiClientContext =
317 (struct ChppWifiClientState *)clientContext;
318
319 chppClientCloseOpenRequests(&wifiClientContext->client, &kWifiClientConfig,
320 false /* clearOnly */);
321 chppCheckWifiScanEventNotificationReset();
322
323 if (wifiClientContext->client.openState != CHPP_OPEN_STATE_OPENED &&
324 !wifiClientContext->client.pseudoOpen) {
325 CHPP_LOGW("WiFi client reset but wasn't open");
326 } else {
327 CHPP_LOGI("WiFi client reopening from state=%" PRIu8,
328 wifiClientContext->client.openState);
329 chppClientSendOpenRequest(&wifiClientContext->client,
330 &wifiClientContext->rRState[CHPP_WIFI_OPEN],
331 CHPP_WIFI_OPEN,
332 /*blocking=*/false);
333 }
334 }
335
336 /**
337 * Notifies the client of being matched to a service.
338 *
339 * @param clientContext Maintains status for each client instance.
340 */
chppWifiClientNotifyMatch(void * clientContext)341 static void chppWifiClientNotifyMatch(void *clientContext) {
342 struct ChppWifiClientState *wifiClientContext =
343 (struct ChppWifiClientState *)clientContext;
344
345 if (wifiClientContext->client.pseudoOpen) {
346 CHPP_LOGD("Pseudo-open WiFi client opening");
347 chppClientSendOpenRequest(&wifiClientContext->client,
348 &wifiClientContext->rRState[CHPP_WIFI_OPEN],
349 CHPP_WIFI_OPEN,
350 /*blocking=*/false);
351 }
352 }
353
354 /**
355 * Restores the state of scan monitoring after an incoming reset.
356 *
357 * @param clientContext Maintains status for each client instance.
358 */
chppWiFiRecoverScanMonitor(struct ChppWifiClientState * clientContext)359 static void chppWiFiRecoverScanMonitor(
360 struct ChppWifiClientState *clientContext) {
361 if (clientContext->scanMonitorEnabled) {
362 CHPP_LOGI("Re-enabling WiFi scan monitoring after reset");
363 clientContext->scanMonitorEnabled = false;
364 clientContext->scanMonitorSilenceCallback = true;
365
366 if (!chppWifiClientConfigureScanMonitor(true)) {
367 clientContext->scanMonitorSilenceCallback = false;
368 CHPP_DEBUG_ASSERT_LOG(
369 false, "Unable to re-enable WiFi scan monitoring after reset");
370 }
371 }
372 }
373
374 /**
375 * Handles the service response for the close client request.
376 *
377 * This function is called from chppDispatchWifiResponse().
378 *
379 * @param clientContext Maintains status for each client instance.
380 * @param buf Input data. Cannot be null.
381 * @param len Length of input data in bytes.
382 */
chppWifiCloseResult(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)383 static void chppWifiCloseResult(struct ChppWifiClientState *clientContext,
384 uint8_t *buf, size_t len) {
385 // TODO
386 UNUSED_VAR(clientContext);
387 UNUSED_VAR(buf);
388 UNUSED_VAR(len);
389 }
390
391 /**
392 * Handles the service response for the get capabilities client request.
393 *
394 * This function is called from chppDispatchWifiResponse().
395 *
396 * @param clientContext Maintains status for each client instance.
397 * @param buf Input data. Cannot be null.
398 * @param len Length of input data in bytes.
399 */
chppWifiGetCapabilitiesResult(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)400 static void chppWifiGetCapabilitiesResult(
401 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
402 if (len < sizeof(struct ChppWifiGetCapabilitiesResponse)) {
403 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
404 CHPP_LOGE("GetCapabilities resp. too short. err=%" PRIu8, rxHeader->error);
405
406 } else {
407 struct ChppWifiGetCapabilitiesParameters *result =
408 &((struct ChppWifiGetCapabilitiesResponse *)buf)->params;
409
410 CHPP_LOGD("chppWifiGetCapabilitiesResult received capabilities=0x%" PRIx32,
411 result->capabilities);
412
413 #ifdef CHPP_WIFI_DEFAULT_CAPABILITIES
414 CHPP_ASSERT_LOG((result->capabilities == CHPP_WIFI_DEFAULT_CAPABILITIES),
415 "Unexpected capability 0x%" PRIx32 " != 0x%" PRIx32,
416 result->capabilities, CHPP_WIFI_DEFAULT_CAPABILITIES);
417 #endif
418
419 clientContext->capabilities = result->capabilities;
420 }
421 }
422
423 /**
424 * Handles the service response for the Configure Scan Monitor client request.
425 *
426 * This function is called from chppDispatchWifiResponse().
427 *
428 * @param clientContext Maintains status for each client instance.
429 * @param buf Input data. Cannot be null.
430 * @param len Length of input data in bytes.
431 */
chppWifiConfigureScanMonitorResult(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)432 static void chppWifiConfigureScanMonitorResult(
433 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
434 UNUSED_VAR(clientContext);
435
436 if (len < sizeof(struct ChppWifiConfigureScanMonitorAsyncResponse)) {
437 // Short response length indicates an error
438
439 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
440 CHPP_LOGE("ScanMonitor resp. too short. err=%" PRIu8, rxHeader->error);
441
442 if (rxHeader->error == CHPP_APP_ERROR_NONE) {
443 rxHeader->error = CHPP_APP_ERROR_INVALID_LENGTH;
444 }
445 gCallbacks->scanMonitorStatusChangeCallback(
446 false, chppAppErrorToChreError(rxHeader->error));
447
448 } else {
449 struct ChppWifiConfigureScanMonitorAsyncResponseParameters *result =
450 &((struct ChppWifiConfigureScanMonitorAsyncResponse *)buf)->params;
451
452 gWifiClientContext.scanMonitorEnabled = result->enabled;
453 CHPP_LOGD(
454 "chppWifiConfigureScanMonitorResult received enable=%d, "
455 "errorCode=%" PRIu8,
456 result->enabled, result->errorCode);
457
458 if (!gWifiClientContext.scanMonitorSilenceCallback) {
459 // Per the scanMonitorStatusChangeCallback API contract, unsolicited
460 // calls to scanMonitorStatusChangeCallback must not be made, and it
461 // should only be invoked as the direct result of an earlier call to
462 // configureScanMonitor.
463 gCallbacks->scanMonitorStatusChangeCallback(result->enabled,
464 result->errorCode);
465 } // Else, the WiFi subsystem has been reset and we are required to
466 // silently reenable the scan monitor.
467
468 gWifiClientContext.scanMonitorSilenceCallback = false;
469 }
470 }
471
472 /**
473 * Handles the service response for the Request Scan Result client request.
474 *
475 * This function is called from chppDispatchWifiResponse().
476 *
477 * @param clientContext Maintains status for each client instance.
478 * @param buf Input data. Cannot be null.
479 * @param len Length of input data in bytes.
480 */
chppWifiRequestScanResult(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)481 static void chppWifiRequestScanResult(struct ChppWifiClientState *clientContext,
482 uint8_t *buf, size_t len) {
483 UNUSED_VAR(clientContext);
484
485 if (len < sizeof(struct ChppWifiRequestScanResponse)) {
486 // Short response length indicates an error
487
488 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
489 CHPP_LOGE("ScanRequest resp. too short. err=%" PRIu8, rxHeader->error);
490
491 if (rxHeader->error == CHPP_APP_ERROR_NONE) {
492 rxHeader->error = CHPP_APP_ERROR_INVALID_LENGTH;
493 }
494 gCallbacks->scanResponseCallback(false,
495 chppAppErrorToChreError(rxHeader->error));
496
497 } else {
498 struct ChppWifiRequestScanResponseParameters *result =
499 &((struct ChppWifiRequestScanResponse *)buf)->params;
500 CHPP_LOGI("Scan request success=%d (at service)", result->pending);
501 gCallbacks->scanResponseCallback(result->pending, result->errorCode);
502 }
503 }
504
505 /**
506 * Handles the service response for the Request Ranging Result client request.
507 *
508 * This function is called from chppDispatchWifiResponse().
509 *
510 * @param clientContext Maintains status for each client instance.
511 * @param buf Input data. Cannot be null.
512 * @param len Length of input data in bytes.
513 */
chppWifiRequestRangingResult(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)514 static void chppWifiRequestRangingResult(
515 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
516 UNUSED_VAR(clientContext);
517 UNUSED_VAR(len);
518
519 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
520
521 if (rxHeader->error != CHPP_APP_ERROR_NONE) {
522 CHPP_LOGE("RangingRequest failed at service err=%" PRIu8, rxHeader->error);
523 gCallbacks->rangingEventCallback(chppAppErrorToChreError(rxHeader->error),
524 NULL);
525
526 } else {
527 CHPP_LOGD("Ranging request accepted at service");
528 }
529 }
530
531 /**
532 * Handles the WiFi scan event service notification.
533 *
534 * This function is called from chppDispatchWifiNotification().
535 *
536 * @param clientContext Maintains status for each client instance.
537 * @param buf Input data. Cannot be null.
538 * @param len Length of input data in bytes.
539 */
chppWifiScanEventNotification(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)540 static void chppWifiScanEventNotification(
541 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
542 UNUSED_VAR(clientContext);
543 CHPP_LOGD("chppWifiScanEventNotification received data len=%" PRIuSIZE, len);
544
545 buf += sizeof(struct ChppAppHeader);
546 len -= sizeof(struct ChppAppHeader);
547
548 struct chreWifiScanEvent *chre =
549 chppWifiScanEventToChre((struct ChppWifiScanEvent *)buf, len);
550
551 if (chre == NULL) {
552 CHPP_LOGE("Scan event conversion failed: len=%" PRIuSIZE, len);
553 } else {
554 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
555 uint64_t correctedTime =
556 chre->referenceTime -
557 (uint64_t)chppTimesyncGetOffset(gWifiClientContext.client.appContext,
558 CHPP_WIFI_MAX_TIMESYNC_AGE_NS);
559 CHPP_LOGD("WiFi scan time corrected from %" PRIu64 "to %" PRIu64,
560 chre->referenceTime / CHPP_NSEC_PER_MSEC,
561 correctedTime / CHPP_NSEC_PER_MSEC);
562 chre->referenceTime = correctedTime;
563 #endif
564
565 CHPP_DEBUG_ASSERT(chppCheckWifiScanEventNotification(chre));
566
567 gCallbacks->scanEventCallback(chre);
568 }
569 }
570
571 /**
572 * Handles the WiFi ranging event service notification.
573 *
574 * This function is called from chppDispatchWifiNotification().
575 *
576 * @param clientContext Maintains status for each client instance.
577 * @param buf Input data. Cannot be null.
578 * @param len Length of input data in bytes.
579 */
chppWifiRangingEventNotification(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)580 static void chppWifiRangingEventNotification(
581 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
582 UNUSED_VAR(clientContext);
583
584 CHPP_LOGD("chppWifiRangingEventNotification received data len=%" PRIuSIZE,
585 len);
586
587 buf += sizeof(struct ChppAppHeader);
588 len -= sizeof(struct ChppAppHeader);
589
590 // Timestamp correction prior to conversion to avoid const casting issues.
591 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
592 struct ChppWifiRangingEvent *event = (struct ChppWifiRangingEvent *)buf;
593
594 for (size_t i = 0; i < event->resultCount; i++) {
595 struct ChppWifiRangingResult *results =
596 (struct ChppWifiRangingResult *)&buf[event->results.offset];
597
598 uint64_t correctedTime =
599 results[i].timestamp -
600 (uint64_t)chppTimesyncGetOffset(gWifiClientContext.client.appContext,
601 CHPP_WIFI_MAX_TIMESYNC_AGE_NS);
602 CHPP_LOGD("WiFi ranging result time corrected from %" PRIu64 "to %" PRIu64,
603 results[i].timestamp / CHPP_NSEC_PER_MSEC,
604 correctedTime / CHPP_NSEC_PER_MSEC);
605 results[i].timestamp = correctedTime;
606 }
607 #endif
608
609 struct chreWifiRangingEvent *chre =
610 chppWifiRangingEventToChre((struct ChppWifiRangingEvent *)buf, len);
611
612 uint8_t error = CHRE_ERROR_NONE;
613 if (chre == NULL) {
614 error = CHRE_ERROR;
615 CHPP_LOGE("Ranging event conversion failed len=%" PRIuSIZE, len);
616 }
617
618 gCallbacks->rangingEventCallback(error, chre);
619 }
620
621 /**
622 * Initializes the WiFi client upon an open request from CHRE and responds
623 * with the result.
624 *
625 * @param systemApi CHRE system function pointers.
626 * @param callbacks CHRE entry points.
627 *
628 * @return True if successful. False otherwise.
629 */
chppWifiClientOpen(const struct chrePalSystemApi * systemApi,const struct chrePalWifiCallbacks * callbacks)630 static bool chppWifiClientOpen(const struct chrePalSystemApi *systemApi,
631 const struct chrePalWifiCallbacks *callbacks) {
632 CHPP_DEBUG_ASSERT(systemApi != NULL);
633 CHPP_DEBUG_ASSERT(callbacks != NULL);
634
635 bool result = false;
636 gSystemApi = systemApi;
637 gCallbacks = callbacks;
638
639 CHPP_LOGD("WiFi client opening");
640
641 if (chppWaitForDiscoveryComplete(gWifiClientContext.client.appContext,
642 CHPP_WIFI_DISCOVERY_TIMEOUT_MS)) {
643 result = chppClientSendOpenRequest(
644 &gWifiClientContext.client, &gWifiClientContext.rRState[CHPP_WIFI_OPEN],
645 CHPP_WIFI_OPEN,
646 /*blocking=*/true);
647 }
648
649 #ifdef CHPP_WIFI_CLIENT_OPEN_ALWAYS_SUCCESS
650 chppClientPseudoOpen(&gWifiClientContext.client);
651 result = true;
652 #endif
653
654 return result;
655 }
656
657 /**
658 * Deinitializes the WiFi client.
659 */
chppWifiClientClose(void)660 static void chppWifiClientClose(void) {
661 // Remote
662 struct ChppAppHeader *request = chppAllocClientRequestCommand(
663 &gWifiClientContext.client, CHPP_WIFI_CLOSE);
664
665 if (request == NULL) {
666 CHPP_LOG_OOM();
667 } else if (chppSendTimestampedRequestAndWait(
668 &gWifiClientContext.client,
669 &gWifiClientContext.rRState[CHPP_WIFI_CLOSE], request,
670 sizeof(*request))) {
671 gWifiClientContext.client.openState = CHPP_OPEN_STATE_CLOSED;
672 gWifiClientContext.capabilities = CHRE_WIFI_CAPABILITIES_NONE;
673 chppClientCloseOpenRequests(&gWifiClientContext.client, &kWifiClientConfig,
674 true /* clearOnly */);
675 }
676 }
677
678 /**
679 * Retrieves a set of flags indicating the WiFi features supported by the
680 * current implementation.
681 *
682 * @return Capabilities flags.
683 */
chppWifiClientGetCapabilities(void)684 static uint32_t chppWifiClientGetCapabilities(void) {
685 #ifdef CHPP_WIFI_DEFAULT_CAPABILITIES
686 uint32_t capabilities = CHPP_WIFI_DEFAULT_CAPABILITIES;
687 #else
688 uint32_t capabilities = CHRE_WIFI_CAPABILITIES_NONE;
689 #endif
690
691 if (gWifiClientContext.capabilities != CHRE_WIFI_CAPABILITIES_NONE) {
692 // Result already cached
693 capabilities = gWifiClientContext.capabilities;
694
695 } else {
696 struct ChppAppHeader *request = chppAllocClientRequestCommand(
697 &gWifiClientContext.client, CHPP_WIFI_GET_CAPABILITIES);
698
699 if (request == NULL) {
700 CHPP_LOG_OOM();
701 } else {
702 if (chppSendTimestampedRequestAndWait(
703 &gWifiClientContext.client,
704 &gWifiClientContext.rRState[CHPP_WIFI_GET_CAPABILITIES], request,
705 sizeof(*request))) {
706 // Success. gWifiClientContext.capabilities is now populated
707 capabilities = gWifiClientContext.capabilities;
708 }
709 }
710 }
711
712 return capabilities;
713 }
714
715 /**
716 * Enables/disables receiving unsolicited scan results (scan monitoring).
717 *
718 * @param enable True to enable.
719 *
720 * @return True indicates the request was sent off to the service.
721 */
chppWifiClientConfigureScanMonitor(bool enable)722 static bool chppWifiClientConfigureScanMonitor(bool enable) {
723 bool result = false;
724
725 struct ChppWifiConfigureScanMonitorAsyncRequest *request =
726 chppAllocClientRequestFixed(
727 &gWifiClientContext.client,
728 struct ChppWifiConfigureScanMonitorAsyncRequest);
729
730 if (request == NULL) {
731 CHPP_LOG_OOM();
732 } else {
733 request->header.command = CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC;
734 request->params.enable = enable;
735 request->params.cookie =
736 &gWifiClientContext.rRState[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC];
737
738 result = chppSendTimestampedRequestOrFail(
739 &gWifiClientContext.client,
740 &gWifiClientContext.rRState[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC],
741 request, sizeof(*request), CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT);
742 }
743
744 return result;
745 }
746
747 /**
748 * Request that the WiFi chipset perform a scan or deliver results from its
749 * cache.
750 *
751 * @param params See chreWifiRequestScanAsync().
752 *
753 * @return True indicates the request was sent off to the service.
754 */
chppWifiClientRequestScan(const struct chreWifiScanParams * params)755 static bool chppWifiClientRequestScan(const struct chreWifiScanParams *params) {
756 struct ChppWifiScanParamsWithHeader *request;
757 size_t requestLen;
758
759 bool result = chppWifiScanParamsFromChre(params, &request, &requestLen);
760
761 if (!result) {
762 CHPP_LOG_OOM();
763 } else {
764 request->header.handle = gWifiClientContext.client.handle;
765 request->header.type = CHPP_MESSAGE_TYPE_CLIENT_REQUEST;
766 request->header.transaction = gWifiClientContext.client.transaction++;
767 request->header.error = CHPP_APP_ERROR_NONE;
768 request->header.command = CHPP_WIFI_REQUEST_SCAN_ASYNC;
769
770 result = chppSendTimestampedRequestOrFail(
771 &gWifiClientContext.client,
772 &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_SCAN_ASYNC], request,
773 requestLen, CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
774 }
775
776 return result;
777 }
778
779 /**
780 * Releases the memory held for the scan event callback.
781 *
782 * @param event Location event to be released.
783 */
chppWifiClientReleaseScanEvent(struct chreWifiScanEvent * event)784 static void chppWifiClientReleaseScanEvent(struct chreWifiScanEvent *event) {
785 if (event->scannedFreqListLen > 0) {
786 void *scannedFreqList = CHPP_CONST_CAST_POINTER(event->scannedFreqList);
787 CHPP_FREE_AND_NULLIFY(scannedFreqList);
788 }
789
790 if (event->resultCount > 0) {
791 void *results = CHPP_CONST_CAST_POINTER(event->results);
792 CHPP_FREE_AND_NULLIFY(results);
793 }
794
795 CHPP_FREE_AND_NULLIFY(event);
796 }
797
798 /**
799 * Request that the WiFi chipset perform RTT ranging.
800 *
801 * @param params See chreWifiRequestRangingAsync().
802 *
803 * @return True indicates the request was sent off to the service.
804 */
chppWifiClientRequestRanging(const struct chreWifiRangingParams * params)805 static bool chppWifiClientRequestRanging(
806 const struct chreWifiRangingParams *params) {
807 struct ChppWifiRangingParamsWithHeader *request;
808 size_t requestLen;
809
810 bool result = chppWifiRangingParamsFromChre(params, &request, &requestLen);
811
812 if (!result) {
813 CHPP_LOG_OOM();
814 } else {
815 request->header.handle = gWifiClientContext.client.handle;
816 request->header.type = CHPP_MESSAGE_TYPE_CLIENT_REQUEST;
817 request->header.transaction = gWifiClientContext.client.transaction++;
818 request->header.error = CHPP_APP_ERROR_NONE;
819 request->header.command = CHPP_WIFI_REQUEST_RANGING_ASYNC;
820
821 result = chppSendTimestampedRequestOrFail(
822 &gWifiClientContext.client,
823 &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_RANGING_ASYNC], request,
824 requestLen, CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
825 }
826
827 return result;
828 }
829
830 /**
831 * Releases the memory held for the RTT ranging event callback.
832 *
833 * @param event Location event to be released.
834 */
chppWifiClientReleaseRangingEvent(struct chreWifiRangingEvent * event)835 static void chppWifiClientReleaseRangingEvent(
836 struct chreWifiRangingEvent *event) {
837 if (event->resultCount > 0) {
838 void *results = CHPP_CONST_CAST_POINTER(event->results);
839 CHPP_FREE_AND_NULLIFY(results);
840 }
841
842 CHPP_FREE_AND_NULLIFY(event);
843 }
844
845 /************************************************
846 * Public Functions
847 ***********************************************/
848
chppRegisterWifiClient(struct ChppAppState * appContext)849 void chppRegisterWifiClient(struct ChppAppState *appContext) {
850 chppRegisterClient(appContext, (void *)&gWifiClientContext,
851 &gWifiClientContext.client, gWifiClientContext.rRState,
852 &kWifiClientConfig);
853 }
854
chppDeregisterWifiClient(struct ChppAppState * appContext)855 void chppDeregisterWifiClient(struct ChppAppState *appContext) {
856 // TODO
857
858 UNUSED_VAR(appContext);
859 }
860
getChppWifiClientState(void)861 struct ChppClientState *getChppWifiClientState(void) {
862 return &gWifiClientContext.client;
863 }
864
865 #ifdef CHPP_CLIENT_ENABLED_WIFI
866
867 #ifdef CHPP_CLIENT_ENABLED_CHRE_WIFI
chrePalWifiGetApi(uint32_t requestedApiVersion)868 const struct chrePalWifiApi *chrePalWifiGetApi(uint32_t requestedApiVersion) {
869 #else
870 const struct chrePalWifiApi *chppPalWifiGetApi(uint32_t requestedApiVersion) {
871 #endif
872
873 static const struct chrePalWifiApi api = {
874 .moduleVersion = CHPP_PAL_WIFI_API_VERSION,
875 .open = chppWifiClientOpen,
876 .close = chppWifiClientClose,
877 .getCapabilities = chppWifiClientGetCapabilities,
878 .configureScanMonitor = chppWifiClientConfigureScanMonitor,
879 .requestScan = chppWifiClientRequestScan,
880 .releaseScanEvent = chppWifiClientReleaseScanEvent,
881 .requestRanging = chppWifiClientRequestRanging,
882 .releaseRangingEvent = chppWifiClientReleaseRangingEvent,
883 };
884
885 CHPP_STATIC_ASSERT(
886 CHRE_PAL_WIFI_API_CURRENT_VERSION == CHPP_PAL_WIFI_API_VERSION,
887 "A newer CHRE PAL API version is available. Please update.");
888
889 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(api.moduleVersion,
890 requestedApiVersion)) {
891 return NULL;
892 } else {
893 return &api;
894 }
895 }
896
897 #endif
898