• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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