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
501 // TODO(b/193540354): Remove when resolved
502 {
503 static uint32_t sNumConsecutiveError = 0;
504 if (result->errorCode != CHRE_ERROR_NONE) {
505 sNumConsecutiveError++;
506 } else {
507 sNumConsecutiveError = 0;
508 }
509 if (sNumConsecutiveError > 20) {
510 CHPP_ASSERT("Too many consecutive WiFi scan errors");
511 }
512 }
513
514 CHPP_LOGI("Scan request success=%d (at service)", result->pending);
515 gCallbacks->scanResponseCallback(result->pending, result->errorCode);
516 }
517 }
518
519 /**
520 * Handles the service response for the Request Ranging Result client request.
521 *
522 * This function is called from chppDispatchWifiResponse().
523 *
524 * @param clientContext Maintains status for each client instance.
525 * @param buf Input data. Cannot be null.
526 * @param len Length of input data in bytes.
527 */
chppWifiRequestRangingResult(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)528 static void chppWifiRequestRangingResult(
529 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
530 UNUSED_VAR(clientContext);
531 UNUSED_VAR(len);
532
533 struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
534
535 if (rxHeader->error != CHPP_APP_ERROR_NONE) {
536 CHPP_LOGE("RangingRequest failed at service err=%" PRIu8, rxHeader->error);
537 gCallbacks->rangingEventCallback(chppAppErrorToChreError(rxHeader->error),
538 NULL);
539
540 } else {
541 CHPP_LOGD("Ranging request accepted at service");
542 }
543 }
544
545 /**
546 * Handles the WiFi scan event service notification.
547 *
548 * This function is called from chppDispatchWifiNotification().
549 *
550 * @param clientContext Maintains status for each client instance.
551 * @param buf Input data. Cannot be null.
552 * @param len Length of input data in bytes.
553 */
chppWifiScanEventNotification(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)554 static void chppWifiScanEventNotification(
555 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
556 UNUSED_VAR(clientContext);
557 CHPP_LOGD("chppWifiScanEventNotification received data len=%" PRIuSIZE, len);
558
559 buf += sizeof(struct ChppAppHeader);
560 len -= sizeof(struct ChppAppHeader);
561
562 struct chreWifiScanEvent *chre =
563 chppWifiScanEventToChre((struct ChppWifiScanEvent *)buf, len);
564
565 if (chre == NULL) {
566 CHPP_LOGE("Scan event conversion failed: len=%" PRIuSIZE, len);
567 } else {
568 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
569 uint64_t correctedTime =
570 chre->referenceTime -
571 (uint64_t)chppTimesyncGetOffset(gWifiClientContext.client.appContext,
572 CHPP_WIFI_MAX_TIMESYNC_AGE_NS);
573 CHPP_LOGD("WiFi scan time corrected from %" PRIu64 "to %" PRIu64,
574 chre->referenceTime / CHPP_NSEC_PER_MSEC,
575 correctedTime / CHPP_NSEC_PER_MSEC);
576 chre->referenceTime = correctedTime;
577 #endif
578
579 CHPP_DEBUG_ASSERT(chppCheckWifiScanEventNotification(chre));
580
581 gCallbacks->scanEventCallback(chre);
582 }
583 }
584
585 /**
586 * Handles the WiFi ranging event service notification.
587 *
588 * This function is called from chppDispatchWifiNotification().
589 *
590 * @param clientContext Maintains status for each client instance.
591 * @param buf Input data. Cannot be null.
592 * @param len Length of input data in bytes.
593 */
chppWifiRangingEventNotification(struct ChppWifiClientState * clientContext,uint8_t * buf,size_t len)594 static void chppWifiRangingEventNotification(
595 struct ChppWifiClientState *clientContext, uint8_t *buf, size_t len) {
596 UNUSED_VAR(clientContext);
597
598 CHPP_LOGD("chppWifiRangingEventNotification received data len=%" PRIuSIZE,
599 len);
600
601 buf += sizeof(struct ChppAppHeader);
602 len -= sizeof(struct ChppAppHeader);
603
604 // Timestamp correction prior to conversion to avoid const casting issues.
605 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
606 struct ChppWifiRangingEvent *event = (struct ChppWifiRangingEvent *)buf;
607
608 for (size_t i = 0; i < event->resultCount; i++) {
609 struct ChppWifiRangingResult *results =
610 (struct ChppWifiRangingResult *)&buf[event->results.offset];
611
612 uint64_t correctedTime =
613 results[i].timestamp -
614 (uint64_t)chppTimesyncGetOffset(gWifiClientContext.client.appContext,
615 CHPP_WIFI_MAX_TIMESYNC_AGE_NS);
616 CHPP_LOGD("WiFi ranging result time corrected from %" PRIu64 "to %" PRIu64,
617 results[i].timestamp / CHPP_NSEC_PER_MSEC,
618 correctedTime / CHPP_NSEC_PER_MSEC);
619 results[i].timestamp = correctedTime;
620 }
621 #endif
622
623 struct chreWifiRangingEvent *chre =
624 chppWifiRangingEventToChre((struct ChppWifiRangingEvent *)buf, len);
625
626 uint8_t error = CHRE_ERROR_NONE;
627 if (chre == NULL) {
628 error = CHRE_ERROR;
629 CHPP_LOGE("Ranging event conversion failed len=%" PRIuSIZE, len);
630 }
631
632 gCallbacks->rangingEventCallback(error, chre);
633 }
634
635 /**
636 * Initializes the WiFi client upon an open request from CHRE and responds
637 * with the result.
638 *
639 * @param systemApi CHRE system function pointers.
640 * @param callbacks CHRE entry points.
641 *
642 * @return True if successful. False otherwise.
643 */
chppWifiClientOpen(const struct chrePalSystemApi * systemApi,const struct chrePalWifiCallbacks * callbacks)644 static bool chppWifiClientOpen(const struct chrePalSystemApi *systemApi,
645 const struct chrePalWifiCallbacks *callbacks) {
646 CHPP_DEBUG_ASSERT(systemApi != NULL);
647 CHPP_DEBUG_ASSERT(callbacks != NULL);
648
649 bool result = false;
650 gSystemApi = systemApi;
651 gCallbacks = callbacks;
652
653 CHPP_LOGD("WiFi client opening");
654
655 if (chppWaitForDiscoveryComplete(gWifiClientContext.client.appContext,
656 CHPP_WIFI_DISCOVERY_TIMEOUT_MS)) {
657 result = chppClientSendOpenRequest(
658 &gWifiClientContext.client, &gWifiClientContext.rRState[CHPP_WIFI_OPEN],
659 CHPP_WIFI_OPEN,
660 /*blocking=*/true);
661 }
662
663 #ifdef CHPP_WIFI_CLIENT_OPEN_ALWAYS_SUCCESS
664 chppClientPseudoOpen(&gWifiClientContext.client);
665 result = true;
666 #endif
667
668 return result;
669 }
670
671 /**
672 * Deinitializes the WiFi client.
673 */
chppWifiClientClose(void)674 static void chppWifiClientClose(void) {
675 // Remote
676 struct ChppAppHeader *request = chppAllocClientRequestCommand(
677 &gWifiClientContext.client, CHPP_WIFI_CLOSE);
678
679 if (request == NULL) {
680 CHPP_LOG_OOM();
681 } else if (chppSendTimestampedRequestAndWait(
682 &gWifiClientContext.client,
683 &gWifiClientContext.rRState[CHPP_WIFI_CLOSE], request,
684 sizeof(*request))) {
685 gWifiClientContext.client.openState = CHPP_OPEN_STATE_CLOSED;
686 gWifiClientContext.capabilities = CHRE_WIFI_CAPABILITIES_NONE;
687 chppClientCloseOpenRequests(&gWifiClientContext.client, &kWifiClientConfig,
688 true /* clearOnly */);
689 }
690 }
691
692 /**
693 * Retrieves a set of flags indicating the WiFi features supported by the
694 * current implementation.
695 *
696 * @return Capabilities flags.
697 */
chppWifiClientGetCapabilities(void)698 static uint32_t chppWifiClientGetCapabilities(void) {
699 #ifdef CHPP_WIFI_DEFAULT_CAPABILITIES
700 uint32_t capabilities = CHPP_WIFI_DEFAULT_CAPABILITIES;
701 #else
702 uint32_t capabilities = CHRE_WIFI_CAPABILITIES_NONE;
703 #endif
704
705 if (gWifiClientContext.capabilities != CHRE_WIFI_CAPABILITIES_NONE) {
706 // Result already cached
707 capabilities = gWifiClientContext.capabilities;
708
709 } else {
710 struct ChppAppHeader *request = chppAllocClientRequestCommand(
711 &gWifiClientContext.client, CHPP_WIFI_GET_CAPABILITIES);
712
713 if (request == NULL) {
714 CHPP_LOG_OOM();
715 } else {
716 if (chppSendTimestampedRequestAndWait(
717 &gWifiClientContext.client,
718 &gWifiClientContext.rRState[CHPP_WIFI_GET_CAPABILITIES], request,
719 sizeof(*request))) {
720 // Success. gWifiClientContext.capabilities is now populated
721 capabilities = gWifiClientContext.capabilities;
722 }
723 }
724 }
725
726 return capabilities;
727 }
728
729 /**
730 * Enables/disables receiving unsolicited scan results (scan monitoring).
731 *
732 * @param enable True to enable.
733 *
734 * @return True indicates the request was sent off to the service.
735 */
chppWifiClientConfigureScanMonitor(bool enable)736 static bool chppWifiClientConfigureScanMonitor(bool enable) {
737 bool result = false;
738
739 struct ChppWifiConfigureScanMonitorAsyncRequest *request =
740 chppAllocClientRequestFixed(
741 &gWifiClientContext.client,
742 struct ChppWifiConfigureScanMonitorAsyncRequest);
743
744 if (request == NULL) {
745 CHPP_LOG_OOM();
746 } else {
747 request->header.command = CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC;
748 request->params.enable = enable;
749 request->params.cookie =
750 &gWifiClientContext.rRState[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC];
751
752 result = chppSendTimestampedRequestOrFail(
753 &gWifiClientContext.client,
754 &gWifiClientContext.rRState[CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC],
755 request, sizeof(*request), CHPP_CLIENT_REQUEST_TIMEOUT_DEFAULT);
756 }
757
758 return result;
759 }
760
761 /**
762 * Request that the WiFi chipset perform a scan or deliver results from its
763 * cache.
764 *
765 * @param params See chreWifiRequestScanAsync().
766 *
767 * @return True indicates the request was sent off to the service.
768 */
chppWifiClientRequestScan(const struct chreWifiScanParams * params)769 static bool chppWifiClientRequestScan(const struct chreWifiScanParams *params) {
770 struct ChppWifiScanParamsWithHeader *request;
771 size_t requestLen;
772
773 bool result = chppWifiScanParamsFromChre(params, &request, &requestLen);
774
775 if (!result) {
776 CHPP_LOG_OOM();
777 } else {
778 request->header.handle = gWifiClientContext.client.handle;
779 request->header.type = CHPP_MESSAGE_TYPE_CLIENT_REQUEST;
780 request->header.transaction = gWifiClientContext.client.transaction++;
781 request->header.error = CHPP_APP_ERROR_NONE;
782 request->header.command = CHPP_WIFI_REQUEST_SCAN_ASYNC;
783
784 result = chppSendTimestampedRequestOrFail(
785 &gWifiClientContext.client,
786 &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_SCAN_ASYNC], request,
787 requestLen, CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
788 }
789
790 return result;
791 }
792
793 /**
794 * Releases the memory held for the scan event callback.
795 *
796 * @param event Location event to be released.
797 */
chppWifiClientReleaseScanEvent(struct chreWifiScanEvent * event)798 static void chppWifiClientReleaseScanEvent(struct chreWifiScanEvent *event) {
799 if (event->scannedFreqListLen > 0) {
800 void *scannedFreqList = CHPP_CONST_CAST_POINTER(event->scannedFreqList);
801 CHPP_FREE_AND_NULLIFY(scannedFreqList);
802 }
803
804 if (event->resultCount > 0) {
805 void *results = CHPP_CONST_CAST_POINTER(event->results);
806 CHPP_FREE_AND_NULLIFY(results);
807 }
808
809 CHPP_FREE_AND_NULLIFY(event);
810 }
811
812 /**
813 * Request that the WiFi chipset perform RTT ranging.
814 *
815 * @param params See chreWifiRequestRangingAsync().
816 *
817 * @return True indicates the request was sent off to the service.
818 */
chppWifiClientRequestRanging(const struct chreWifiRangingParams * params)819 static bool chppWifiClientRequestRanging(
820 const struct chreWifiRangingParams *params) {
821 struct ChppWifiRangingParamsWithHeader *request;
822 size_t requestLen;
823
824 bool result = chppWifiRangingParamsFromChre(params, &request, &requestLen);
825
826 if (!result) {
827 CHPP_LOG_OOM();
828 } else {
829 request->header.handle = gWifiClientContext.client.handle;
830 request->header.type = CHPP_MESSAGE_TYPE_CLIENT_REQUEST;
831 request->header.transaction = gWifiClientContext.client.transaction++;
832 request->header.error = CHPP_APP_ERROR_NONE;
833 request->header.command = CHPP_WIFI_REQUEST_RANGING_ASYNC;
834
835 result = chppSendTimestampedRequestOrFail(
836 &gWifiClientContext.client,
837 &gWifiClientContext.rRState[CHPP_WIFI_REQUEST_RANGING_ASYNC], request,
838 requestLen, CHRE_WIFI_RANGING_RESULT_TIMEOUT_NS);
839 }
840
841 return result;
842 }
843
844 /**
845 * Releases the memory held for the RTT ranging event callback.
846 *
847 * @param event Location event to be released.
848 */
chppWifiClientReleaseRangingEvent(struct chreWifiRangingEvent * event)849 static void chppWifiClientReleaseRangingEvent(
850 struct chreWifiRangingEvent *event) {
851 if (event->resultCount > 0) {
852 void *results = CHPP_CONST_CAST_POINTER(event->results);
853 CHPP_FREE_AND_NULLIFY(results);
854 }
855
856 CHPP_FREE_AND_NULLIFY(event);
857 }
858
859 /************************************************
860 * Public Functions
861 ***********************************************/
862
chppRegisterWifiClient(struct ChppAppState * appContext)863 void chppRegisterWifiClient(struct ChppAppState *appContext) {
864 chppRegisterClient(appContext, (void *)&gWifiClientContext,
865 &gWifiClientContext.client, gWifiClientContext.rRState,
866 &kWifiClientConfig);
867 }
868
chppDeregisterWifiClient(struct ChppAppState * appContext)869 void chppDeregisterWifiClient(struct ChppAppState *appContext) {
870 // TODO
871
872 UNUSED_VAR(appContext);
873 }
874
getChppWifiClientState(void)875 struct ChppClientState *getChppWifiClientState(void) {
876 return &gWifiClientContext.client;
877 }
878
879 #ifdef CHPP_CLIENT_ENABLED_WIFI
880
881 #ifdef CHPP_CLIENT_ENABLED_CHRE_WIFI
chrePalWifiGetApi(uint32_t requestedApiVersion)882 const struct chrePalWifiApi *chrePalWifiGetApi(uint32_t requestedApiVersion) {
883 #else
884 const struct chrePalWifiApi *chppPalWifiGetApi(uint32_t requestedApiVersion) {
885 #endif
886
887 static const struct chrePalWifiApi api = {
888 .moduleVersion = CHPP_PAL_WIFI_API_VERSION,
889 .open = chppWifiClientOpen,
890 .close = chppWifiClientClose,
891 .getCapabilities = chppWifiClientGetCapabilities,
892 .configureScanMonitor = chppWifiClientConfigureScanMonitor,
893 .requestScan = chppWifiClientRequestScan,
894 .releaseScanEvent = chppWifiClientReleaseScanEvent,
895 .requestRanging = chppWifiClientRequestRanging,
896 .releaseRangingEvent = chppWifiClientReleaseRangingEvent,
897 };
898
899 CHPP_STATIC_ASSERT(
900 CHRE_PAL_WIFI_API_CURRENT_VERSION == CHPP_PAL_WIFI_API_VERSION,
901 "A newer CHRE PAL API version is available. Please update.");
902
903 if (!CHRE_PAL_VERSIONS_ARE_COMPATIBLE(api.moduleVersion,
904 requestedApiVersion)) {
905 return NULL;
906 } else {
907 return &api;
908 }
909 }
910
911 #endif
912