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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 863 void chppRegisterWifiClient(struct ChppAppState *appContext) { 864 chppRegisterClient(appContext, (void *)&gWifiClientContext, 865 &gWifiClientContext.client, gWifiClientContext.rRState, 866 &kWifiClientConfig); 867 } 868 869 void chppDeregisterWifiClient(struct ChppAppState *appContext) { 870 // TODO 871 872 UNUSED_VAR(appContext); 873 } 874 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 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