/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "chpp/services/wifi.h" #include #include #include #include "chpp/common/standard_uuids.h" #include "chpp/common/wifi.h" #include "chpp/common/wifi_types.h" #include "chpp/common/wifi_utils.h" #include "chpp/log.h" #include "chpp/macros.h" #include "chpp/services.h" #include "chre/pal/wifi.h" /************************************************ * Prototypes ***********************************************/ static enum ChppAppErrorCode chppDispatchWifiRequest(void *serviceContext, uint8_t *buf, size_t len); static void chppWifiServiceNotifyReset(void *serviceContext); /************************************************ * Private Definitions ***********************************************/ /** * Configuration parameters for this service */ static const struct ChppService kWifiServiceConfig = { .descriptor.uuid = CHPP_UUID_WIFI_STANDARD, // Human-readable name .descriptor.name = "WiFi", // Version .descriptor.version.major = 1, .descriptor.version.minor = 0, .descriptor.version.patch = 0, // Notifies service if CHPP is reset .resetNotifierFunctionPtr = &chppWifiServiceNotifyReset, // Client request dispatch function pointer .requestDispatchFunctionPtr = &chppDispatchWifiRequest, // Client notification dispatch function pointer .notificationDispatchFunctionPtr = NULL, // Not supported // Min length is the entire header .minLength = sizeof(struct ChppAppHeader), }; /** * Structure to maintain state for the WiFi service and its Request/Response * (RR) functionality. */ struct ChppWifiServiceState { struct ChppServiceState service; // WiFi service state const struct chrePalWifiApi *api; // WiFi PAL API // Based on chre/pal/wifi.h and chrePalWifiApi struct ChppRequestResponseState open; // Service init state struct ChppRequestResponseState close; // Service deinit state struct ChppRequestResponseState getCapabilities; // Get Capabilities state struct ChppRequestResponseState configureScanMonitorAsync; // Configure scan monitor state struct ChppRequestResponseState requestScanAsync; // Request scan state struct ChppRequestResponseState requestRangingAsync; // Request ranging state struct ChppRequestResponseState requestNanSubscribe; // Request Nan Subscription state struct ChppRequestResponseState requestNanSubscribeCancel; // Request Nan Subscription cancelation state struct ChppRequestResponseState requestNanRangingAsync; // Request NAN ranging state }; // Note: The CHRE PAL API only allows for one definition - see comment in WWAN // service for details. // Note: There is no notion of a cookie in the CHRE WiFi API so we need to use // the global service state (gWifiServiceContext) directly in all callbacks. struct ChppWifiServiceState gWifiServiceContext; /************************************************ * Prototypes ***********************************************/ static enum ChppAppErrorCode chppWifiServiceOpen( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader); static enum ChppAppErrorCode chppWifiServiceClose( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader); static enum ChppAppErrorCode chppWifiServiceGetCapabilities( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader); static enum ChppAppErrorCode chppWifiServiceConfigureScanMonitorAsync( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len); static enum ChppAppErrorCode chppWifiServiceRequestScanAsync( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len); static enum ChppAppErrorCode chppWifiServiceRequestRangingAsync( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len); static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribe( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len); static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribeCancel( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len); static bool chppWifiServiceRequestNanRanging( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len); static void chppWifiServiceScanMonitorStatusChangeCallback(bool enabled, uint8_t errorCode); static void chppWifiServiceScanResponseCallback(bool pending, uint8_t errorCode); static void chppWifiServiceScanEventCallback(struct chreWifiScanEvent *event); static void chppWifiServiceRangingEventCallback( uint8_t errorCode, struct chreWifiRangingEvent *event); static void chppWifiServiceNanIdentifierCallback(uint8_t errorCode, uint32_t subscriptionId); static void chppWifiServiceNanDiscoveryCallback( struct chreWifiNanDiscoveryEvent *event); static void chppWifiServiceNanLostCallback(uint32_t subscriptionId, uint32_t publisherId); static void chppWifiServiceNanTerminatedCallback(uint32_t reason, uint32_t subscriptionId); static void chppWifiServiceNanSubscriptionCanceledCallback( uint8_t errorCode, uint32_t subscriptionId); /************************************************ * Private Functions ***********************************************/ /** * Dispatches a client request from the transport layer that is determined to be * for the WiFi service. If the result of the dispatch is an error, this * function responds to the client with the same error. * * This function is called from the app layer using its function pointer given * during service registration. * * @param serviceContext Maintains status for each service instance. * @param buf Input data. Cannot be null. * @param len Length of input data in bytes. * * @return Indicates the result of this function call. */ static enum ChppAppErrorCode chppDispatchWifiRequest(void *serviceContext, uint8_t *buf, size_t len) { struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf; buf += sizeof(struct ChppAppHeader); len -= sizeof(struct ChppAppHeader); struct ChppWifiServiceState *wifiServiceContext = (struct ChppWifiServiceState *)serviceContext; struct ChppRequestResponseState *rRState = NULL; enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; bool dispatched = true; switch (rxHeader->command) { case CHPP_WIFI_OPEN: { rRState = &wifiServiceContext->open; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceOpen(wifiServiceContext, rxHeader); break; } case CHPP_WIFI_CLOSE: { rRState = &wifiServiceContext->close; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceClose(wifiServiceContext, rxHeader); break; } case CHPP_WIFI_GET_CAPABILITIES: { rRState = &wifiServiceContext->getCapabilities; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceGetCapabilities(wifiServiceContext, rxHeader); break; } case CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC: { rRState = &wifiServiceContext->configureScanMonitorAsync; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceConfigureScanMonitorAsync(wifiServiceContext, rxHeader, buf, len); break; } case CHPP_WIFI_REQUEST_SCAN_ASYNC: { rRState = &wifiServiceContext->requestScanAsync; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceRequestScanAsync(wifiServiceContext, rxHeader, buf, len); break; } case CHPP_WIFI_REQUEST_RANGING_ASYNC: { rRState = &wifiServiceContext->requestRangingAsync; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceRequestRangingAsync(wifiServiceContext, rxHeader, buf, len); break; } case CHPP_WIFI_REQUEST_NAN_SUB: { rRState = &wifiServiceContext->requestNanSubscribe; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceRequestNanSubscribe(wifiServiceContext, rxHeader, buf, len); break; } case CHPP_WIFI_REQUEST_NAN_SUB_CANCEL: { rRState = &wifiServiceContext->requestNanSubscribeCancel; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceRequestNanSubscribeCancel(wifiServiceContext, rxHeader, buf, len); break; }; case CHPP_WIFI_REQUEST_NAN_RANGING_ASYNC: { rRState = &wifiServiceContext->requestNanRangingAsync; chppServiceTimestampRequest(rRState, rxHeader); error = chppWifiServiceRequestNanRanging(wifiServiceContext, rxHeader, buf, len); break; } default: { dispatched = false; error = CHPP_APP_ERROR_INVALID_COMMAND; break; } } if (dispatched == true && error != CHPP_APP_ERROR_NONE) { // Request was dispatched but an error was returned. Close out // chppServiceTimestampRequest() chppServiceTimestampResponse(rRState); } return error; } /** * Initializes the WiFi service upon an open request from the client and * responds to the client with the result. * * @param serviceContext Maintains status for each service instance. * @param requestHeader App layer header of the request. * * @return Indicates the result of this function call. */ static enum ChppAppErrorCode chppWifiServiceOpen( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader) { static const struct chrePalWifiCallbacks palCallbacks = { .scanMonitorStatusChangeCallback = chppWifiServiceScanMonitorStatusChangeCallback, .scanResponseCallback = chppWifiServiceScanResponseCallback, .scanEventCallback = chppWifiServiceScanEventCallback, .rangingEventCallback = chppWifiServiceRangingEventCallback, .nanServiceIdentifierCallback = chppWifiServiceNanIdentifierCallback, .nanServiceDiscoveryCallback = chppWifiServiceNanDiscoveryCallback, .nanServiceLostCallback = chppWifiServiceNanLostCallback, .nanServiceTerminatedCallback = chppWifiServiceNanTerminatedCallback, .nanSubscriptionCanceledCallback = chppWifiServiceNanSubscriptionCanceledCallback, }; enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; if (wifiServiceContext->service.openState == CHPP_OPEN_STATE_OPENED) { CHPP_DEBUG_ASSERT_LOG(false, "WiFi service already open"); error = CHPP_APP_ERROR_INVALID_COMMAND; } else if (!wifiServiceContext->api->open( wifiServiceContext->service.appContext->systemApi, &palCallbacks)) { CHPP_DEBUG_ASSERT_LOG(false, "WiFi PAL open failed"); error = CHPP_APP_ERROR_BEYOND_CHPP; } else { CHPP_LOGI("WiFi service opened"); wifiServiceContext->service.openState = CHPP_OPEN_STATE_OPENED; struct ChppAppHeader *response = chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); error = CHPP_APP_ERROR_OOM; } else { chppSendTimestampedResponseOrFail(&wifiServiceContext->service, &wifiServiceContext->open, response, responseLen); } } return error; } /** * Deinitializes the WiFi service. * * @param serviceContext Maintains status for each service instance. * @param requestHeader App layer header of the request. * * @return Indicates the result of this function call. */ static enum ChppAppErrorCode chppWifiServiceClose( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader) { enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; wifiServiceContext->api->close(); wifiServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED; CHPP_LOGI("WiFi service closed"); struct ChppAppHeader *response = chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); error = CHPP_APP_ERROR_OOM; } else { chppSendTimestampedResponseOrFail(&wifiServiceContext->service, &wifiServiceContext->close, response, responseLen); } return error; } /** * Notifies the service of an incoming reset. * * @param serviceContext Maintains status for each service instance. */ static void chppWifiServiceNotifyReset(void *serviceContext) { struct ChppWifiServiceState *wifiServiceContext = (struct ChppWifiServiceState *)serviceContext; if (wifiServiceContext->service.openState != CHPP_OPEN_STATE_OPENED) { CHPP_LOGW("WiFi service reset but wasn't open"); } else { CHPP_LOGI("WiFi service reset. Closing"); wifiServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED; wifiServiceContext->api->close(); } } /** * Retrieves a set of flags indicating the WiFi features supported by the * current implementation. * * @param serviceContext Maintains status for each service instance. * @param requestHeader App layer header of the request. * * @return Indicates the result of this function call. */ static enum ChppAppErrorCode chppWifiServiceGetCapabilities( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader) { enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; struct ChppWifiGetCapabilitiesResponse *response = chppAllocServiceResponseFixed(requestHeader, struct ChppWifiGetCapabilitiesResponse); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); error = CHPP_APP_ERROR_OOM; } else { response->params.capabilities = wifiServiceContext->api->getCapabilities(); CHPP_LOGD("chppWifiServiceGetCapabilities returning 0x%" PRIx32 ", %" PRIuSIZE " bytes", response->params.capabilities, responseLen); chppSendTimestampedResponseOrFail(&wifiServiceContext->service, &wifiServiceContext->getCapabilities, response, responseLen); } return error; } /** * Configures whether scanEventCallback receives unsolicited scan results, i.e. * the results of scans not performed at the request of CHRE. * * This function returns an error code synchronously. * A subsequent call to chppWifiServiceScanMonitorStatusChangeCallback() will be * used to communicate the result of this request (as a service response). * * @param serviceContext Maintains status for each service instance. * @param requestHeader App layer header of the request. * @param buf Input data. Cannot be null. * @param len Length of input data in bytes. * * @return Indicates the result of this function call. */ static enum ChppAppErrorCode chppWifiServiceConfigureScanMonitorAsync( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) { UNUSED_VAR(requestHeader); enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; if (len < sizeof(bool)) { error = CHPP_APP_ERROR_INVALID_ARG; } else { bool *enable = (bool *)buf; if (!wifiServiceContext->api->configureScanMonitor(*enable)) { error = CHPP_APP_ERROR_UNSPECIFIED; } } return error; } /** * Request that the WiFi chipset perform a scan, or deliver results from its * cache if the parameters allow for it. * * This function returns an error code synchronously. * A subsequent call to chppWifiServiceScanResponseCallback() will be used to * communicate the result of this request (as a service response). * A subsequent call to chppWifiServiceScanEventCallback() will be used to * communicate the scan results (as a service notification). * * @param serviceContext Maintains status for each service instance. * @param requestHeader App layer header of the request. * @param buf Input data. Cannot be null. * @param len Length of input data in bytes. * * @return Indicates the result of this function call. */ static enum ChppAppErrorCode chppWifiServiceRequestScanAsync( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) { UNUSED_VAR(requestHeader); enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; struct chreWifiScanParams *chre = chppWifiScanParamsToChre((struct ChppWifiScanParams *)buf, len); if (chre == NULL) { CHPP_LOGE( "WifiServiceRequestScanAsync CHPP -> CHRE conversion failed. Input " "len=%" PRIuSIZE, len); error = CHPP_APP_ERROR_INVALID_ARG; } else { if (!wifiServiceContext->api->requestScan(chre)) { error = CHPP_APP_ERROR_UNSPECIFIED; } if (chre->frequencyListLen > 0) { void *frequencyList = CHPP_CONST_CAST_POINTER(chre->frequencyList); CHPP_FREE_AND_NULLIFY(frequencyList); } if (chre->ssidListLen > 0) { void *ssidList = CHPP_CONST_CAST_POINTER(chre->ssidList); CHPP_FREE_AND_NULLIFY(ssidList); } CHPP_FREE_AND_NULLIFY(chre); } return error; } /** * Request that the WiFi chipset perform RTT ranging against a set of access * points specified in params. * * This function returns an error code synchronously. * A subsequent call to chppWifiServiceRangingEventCallback() will be used to * communicate the ranging results (as a service notification). * * @param serviceContext Maintains status for each service instance. * @param requestHeader App layer header of the request. * @param buf Input data. Cannot be null. * @param len Length of input data in bytes. * * @return Indicates the result of this function call. */ static enum ChppAppErrorCode chppWifiServiceRequestRangingAsync( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) { UNUSED_VAR(requestHeader); enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; struct chreWifiRangingParams *chre = chppWifiRangingParamsToChre((struct ChppWifiRangingParams *)buf, len); if (chre == NULL) { CHPP_LOGE( "WifiServiceRequestRangingAsync CHPP -> CHRE conversion failed. Input " "len=%" PRIuSIZE, len); error = CHPP_APP_ERROR_INVALID_ARG; } else { if (!wifiServiceContext->api->requestRanging(chre)) { error = CHPP_APP_ERROR_UNSPECIFIED; } else { struct ChppAppHeader *response = chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); error = CHPP_APP_ERROR_OOM; } else { chppSendTimestampedResponseOrFail( &wifiServiceContext->service, &wifiServiceContext->requestRangingAsync, response, responseLen); } } if (chre->targetListLen > 0) { void *targetList = CHPP_CONST_CAST_POINTER(chre->targetList); CHPP_FREE_AND_NULLIFY(targetList); } CHPP_FREE_AND_NULLIFY(chre); } return error; } static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribe( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) { enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; struct chreWifiNanSubscribeConfig *chreConfig = chppWifiNanSubscribeConfigToChre((struct ChppWifiNanSubscribeConfig *)buf, len); if (chreConfig == NULL) { CHPP_LOGE( "WifiServiceNanSubscribeConfig CHPP -> CHRE conversion failed." "Input len: %" PRIuSIZE, len); error = CHPP_APP_ERROR_INVALID_ARG; } else { if (!wifiServiceContext->api->nanSubscribe(chreConfig)) { error = CHPP_APP_ERROR_UNSPECIFIED; } else { struct ChppAppHeader *response = chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); error = CHPP_APP_ERROR_OOM; } else { chppSendTimestampedResponseOrFail( &wifiServiceContext->service, &wifiServiceContext->requestNanSubscribe, response, responseLen); } } } return error; } static enum ChppAppErrorCode chppWifiServiceRequestNanSubscribeCancel( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) { enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; if (len < sizeof(struct ChppWifiNanSubscribeCancelRequest)) { CHPP_LOGE( "WifiServiceRequestNanSubscribecancel invalid input len = %" PRIuSIZE, len); error = CHPP_APP_ERROR_INVALID_ARG; } else { struct ChppWifiNanSubscribeCancelRequest *chppRequest = (struct ChppWifiNanSubscribeCancelRequest *)buf; uint32_t subscriptionId = chppRequest->subscriptionId; if (!wifiServiceContext->api->nanSubscribeCancel(subscriptionId)) { error = CHPP_APP_ERROR_UNSPECIFIED; } else { struct ChppAppHeader *response = chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); error = CHPP_APP_ERROR_OOM; } else { chppSendTimestampedResponseOrFail( &wifiServiceContext->service, &wifiServiceContext->requestNanSubscribeCancel, response, responseLen); } } } return error; } static bool chppWifiServiceRequestNanRanging( struct ChppWifiServiceState *wifiServiceContext, struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) { enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE; struct chreWifiNanRangingParams *chreParams = chppWifiNanRangingParamsToChre( (struct ChppWifiNanRangingParams *)buf, len); if (chreParams == NULL) { CHPP_LOGE( "WifiServiceRequestNanRanging CHPP -> CHRE conversion failed. " "Input len: %" PRIuSIZE, len); error = CHPP_APP_ERROR_INVALID_ARG; } else { if (!wifiServiceContext->api->requestNanRanging(chreParams)) { error = CHPP_APP_ERROR_UNSPECIFIED; } else { struct ChppAppHeader *response = chppAllocServiceResponseFixed(requestHeader, struct ChppAppHeader); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); error = CHPP_APP_ERROR_OOM; } else { chppSendTimestampedResponseOrFail( &wifiServiceContext->service, &wifiServiceContext->requestNanRangingAsync, response, responseLen); } } } return error; } /** * PAL callback with the result of changes to the scan monitor registration * status requested via configureScanMonitor. * * @param enabled true if the scan monitor is currently active * @param errorCode An error code from enum chreError */ static void chppWifiServiceScanMonitorStatusChangeCallback(bool enabled, uint8_t errorCode) { // Recreate request header struct ChppAppHeader requestHeader = { .handle = gWifiServiceContext.service.handle, .transaction = gWifiServiceContext.configureScanMonitorAsync.transaction, .command = CHPP_WIFI_CONFIGURE_SCAN_MONITOR_ASYNC, }; struct ChppWifiConfigureScanMonitorAsyncResponse *response = chppAllocServiceResponseFixed( &requestHeader, struct ChppWifiConfigureScanMonitorAsyncResponse); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); CHPP_ASSERT(false); } else { response->params.enabled = enabled; response->params.errorCode = errorCode; chppSendTimestampedResponseOrFail( &gWifiServiceContext.service, &gWifiServiceContext.configureScanMonitorAsync, response, responseLen); } } /** * PAL callback with the result of a requestScan. * * @param pending true if the request was successful. * @param errorCode An error code from enum chreError. */ static void chppWifiServiceScanResponseCallback(bool pending, uint8_t errorCode) { // Recreate request header struct ChppAppHeader requestHeader = { .handle = gWifiServiceContext.service.handle, .transaction = gWifiServiceContext.requestScanAsync.transaction, .command = CHPP_WIFI_REQUEST_SCAN_ASYNC, }; struct ChppWifiRequestScanResponse *response = chppAllocServiceResponseFixed( &requestHeader, struct ChppWifiRequestScanResponse); size_t responseLen = sizeof(*response); if (response == NULL) { CHPP_LOG_OOM(); CHPP_ASSERT(false); } else { response->params.pending = pending; response->params.errorCode = errorCode; chppSendTimestampedResponseOrFail(&gWifiServiceContext.service, &gWifiServiceContext.requestScanAsync, response, responseLen); } } /** * PAL callback with WiFi scan results. * * @param event Scan result data. */ static void chppWifiServiceScanEventCallback(struct chreWifiScanEvent *event) { // Craft response per parser script struct ChppWifiScanEventWithHeader *notification = NULL; size_t notificationLen = 0; CHPP_DEBUG_ASSERT(chppCheckWifiScanEventNotification(event)); if (!chppWifiScanEventFromChre(event, ¬ification, ¬ificationLen)) { CHPP_LOGE("ScanEvent conversion failed (OOM?). ID=%" PRIu8, gWifiServiceContext.requestScanAsync.transaction); notification = chppMalloc(sizeof(struct ChppAppHeader)); if (notification == NULL) { CHPP_LOG_OOM(); } else { notificationLen = sizeof(struct ChppAppHeader); } } if (notification != NULL) { notification->header.handle = gWifiServiceContext.service.handle; notification->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION; notification->header.transaction = gWifiServiceContext.requestScanAsync.transaction; notification->header.error = (notificationLen > sizeof(struct ChppAppHeader)) ? CHPP_APP_ERROR_NONE : CHPP_APP_ERROR_CONVERSION_FAILED; notification->header.command = CHPP_WIFI_REQUEST_SCAN_ASYNC; chppEnqueueTxDatagramOrFail( gWifiServiceContext.service.appContext->transportContext, notification, notificationLen); } gWifiServiceContext.api->releaseScanEvent(event); } /** * PAL callback with RTT ranging results from the WiFi module. * * @param errorCode An error code from enum chreError. * @param event Ranging data. */ static void chppWifiServiceRangingEventCallback( uint8_t errorCode, struct chreWifiRangingEvent *event) { struct ChppWifiRangingEventWithHeader *notification = NULL; size_t notificationLen = 0; if (!chppWifiRangingEventFromChre(event, ¬ification, ¬ificationLen)) { CHPP_LOGE("RangingEvent conversion failed (OOM?) ID=%" PRIu8, gWifiServiceContext.requestRangingAsync.transaction); notification = chppMalloc(sizeof(struct ChppAppHeader)); if (notification == NULL) { CHPP_LOG_OOM(); } else { notificationLen = sizeof(struct ChppAppHeader); } } if (notification != NULL) { uint16_t command = CHPP_WIFI_REQUEST_RANGING_ASYNC; // Per CHRE's API contract, only one kind of ranging request can be pending // at a time - use the higher of the two for the notification. uint8_t transaction = MAX(gWifiServiceContext.requestRangingAsync.transaction, gWifiServiceContext.requestNanRangingAsync.transaction); notification->header.handle = gWifiServiceContext.service.handle; notification->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION; notification->header.transaction = transaction; notification->header.command = command; notification->header.error = (notificationLen > sizeof(struct ChppAppHeader)) ? CHPP_APP_ERROR_NONE : CHPP_APP_ERROR_CONVERSION_FAILED; if (errorCode != CHRE_ERROR_NONE) { notification->header.error = CHPP_APP_ERROR_BEYOND_CHPP; notificationLen = MIN(notificationLen, sizeof(struct ChppAppHeader)); } chppEnqueueTxDatagramOrFail( gWifiServiceContext.service.appContext->transportContext, notification, notificationLen); } gWifiServiceContext.api->releaseRangingEvent(event); } /** * PAL callback with NAN service subscription identifier information. * * @param errorCode Error code indicating if a NAN subscription failed. The * subscriptionId field is only valid if the error code is * CHRE_ERROR_NONE. * @param subscriptionId The ID assigned to the service subscription request. * This value is only valid if the error code is CHRE_ERROR_NONE. */ static void chppWifiServiceNanIdentifierCallback(uint8_t errorCode, uint32_t subscriptionId) { size_t idLen = sizeof(struct ChppWifiNanServiceIdentifier); struct ChppWifiNanServiceIdentifier *id = chppMalloc(idLen); if (id == NULL) { CHPP_LOG_OOM(); } else { id->header.command = CHPP_WIFI_REQUEST_NAN_SUB; id->header.handle = gWifiServiceContext.service.handle; id->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION; id->header.error = CHPP_APP_ERROR_NONE; id->header.transaction = gWifiServiceContext.requestNanSubscribe.transaction; id->errorCode = errorCode; id->subscriptionId = subscriptionId; chppEnqueueTxDatagramOrFail( gWifiServiceContext.service.appContext->transportContext, id, idLen); } } /** * PAL callback with NAN service discovery information. * * @param event Information about a discovered publishing service. */ static void chppWifiServiceNanDiscoveryCallback( struct chreWifiNanDiscoveryEvent *event) { struct ChppWifiNanDiscoveryEventWithHeader *notif = NULL; size_t notifLen = 0; if (!chppWifiNanDiscoveryEventFromChre(event, ¬if, ¬ifLen)) { CHPP_LOGE("Discovery event conversion failed"); notif = chppMalloc(sizeof(struct ChppAppHeader)); if (notif == NULL) { CHPP_LOG_OOM(); } else { notifLen = sizeof(struct ChppAppHeader); } } if (notif != NULL) { notif->header.handle = gWifiServiceContext.service.handle; notif->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION; notif->header.error = (notifLen > sizeof(struct ChppAppHeader)) ? CHPP_APP_ERROR_NONE : CHPP_APP_ERROR_CONVERSION_FAILED; notif->header.command = CHPP_WIFI_NOTIFICATION_NAN_SERVICE_DISCOVERY; chppEnqueueTxDatagramOrFail( gWifiServiceContext.service.appContext->transportContext, notif, notifLen); } if (event != NULL) { gWifiServiceContext.api->releaseNanDiscoveryEvent(event); } } /** * PAL callback invoked when a publishing NAN service goes away. * * @param subscriptionId ID of the subscribing service. * @param publisherId ID of the publishing service that has gone away. */ static void chppWifiServiceNanLostCallback(uint32_t subscriptionId, uint32_t publisherId) { struct chreWifiNanSessionLostEvent chreEvent = { .id = subscriptionId, .peerId = publisherId, }; struct ChppWifiNanSessionLostEventWithHeader *notif = NULL; size_t notifLen = 0; if (!chppWifiNanSessionLostEventFromChre(&chreEvent, ¬if, ¬ifLen)) { CHPP_LOGE("Session lost event conversion failed"); notif = chppMalloc(sizeof(struct ChppAppHeader)); if (notif == NULL) { CHPP_LOG_OOM(); } else { notifLen = sizeof(struct ChppAppHeader); } } if (notif != NULL) { notif->header.handle = gWifiServiceContext.service.handle; notif->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION; notif->header.error = (notifLen > sizeof(struct ChppAppHeader)) ? CHPP_APP_ERROR_NONE : CHPP_APP_ERROR_CONVERSION_FAILED; notif->header.command = CHPP_WIFI_NOTIFICATION_NAN_SERVICE_LOST; chppEnqueueTxDatagramOrFail( gWifiServiceContext.service.appContext->transportContext, notif, notifLen); } } /** * PAL callback invoked when a NAN service subscription is terminated. * * @param reason Error code indicating the reason for the termination. * @param subscriptionId The subscription ID of the terminated NAN service. */ static void chppWifiServiceNanTerminatedCallback(uint32_t reason, uint32_t subscriptionId) { uint8_t chreReason = (uint8_t)reason; struct chreWifiNanSessionTerminatedEvent chreEvent = { .id = subscriptionId, .reason = chreReason, }; struct ChppWifiNanSessionTerminatedEventWithHeader *notif = NULL; size_t notifLen = 0; if (!chppWifiNanSessionTerminatedEventFromChre(&chreEvent, ¬if, ¬ifLen)) { CHPP_LOGE("Session terminated event conversion failed"); notif = chppMalloc(sizeof(struct ChppAppHeader)); if (notif == NULL) { CHPP_LOG_OOM(); } else { notifLen = sizeof(struct ChppAppHeader); } } if (notif != NULL) { notif->header.handle = gWifiServiceContext.service.handle; notif->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION; notif->header.error = (notifLen > sizeof(struct ChppAppHeader)) ? CHPP_APP_ERROR_NONE : CHPP_APP_ERROR_CONVERSION_FAILED; notif->header.command = CHPP_WIFI_NOTIFICATION_NAN_SERVICE_TERMINATED; chppEnqueueTxDatagramOrFail( gWifiServiceContext.service.appContext->transportContext, notif, notifLen); } } /** * PAL callback invoked when a NAN service subscription is canceled. * * @param errorCode A value in @ref chreError indicating the result of the * cancelation, with CHRE_ERROR_NONE indicating success. * @param subscriptionId The subscription ID of the canceled NAN service. */ static void chppWifiServiceNanSubscriptionCanceledCallback( uint8_t errorCode, uint32_t subscriptionId) { size_t responseLen = sizeof(struct ChppWifiNanSubscriptionCanceledResponse); struct ChppWifiNanSubscriptionCanceledResponse *response = chppMalloc(responseLen); if (response == NULL) { CHPP_LOG_OOM(); } else { response->header.command = CHPP_WIFI_REQUEST_NAN_SUB_CANCEL; response->header.handle = gWifiServiceContext.service.handle; response->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION; response->header.error = CHPP_APP_ERROR_NONE; response->header.transaction = gWifiServiceContext.requestNanSubscribeCancel.transaction; response->errorCode = errorCode; response->subscriptionId = subscriptionId; chppEnqueueTxDatagramOrFail( gWifiServiceContext.service.appContext->transportContext, response, responseLen); } } /************************************************ * Public Functions ***********************************************/ void chppRegisterWifiService(struct ChppAppState *appContext) { gWifiServiceContext.api = chrePalWifiGetApi(CHRE_PAL_WIFI_API_V1_2); chppCheckWifiScanEventNotificationReset(); if (gWifiServiceContext.api == NULL) { CHPP_DEBUG_ASSERT_LOG(false, "WiFi PAL API incompatible. Cannot register service"); } else { gWifiServiceContext.service.appContext = appContext; gWifiServiceContext.service.openState = CHPP_OPEN_STATE_CLOSED; gWifiServiceContext.service.handle = chppRegisterService( appContext, (void *)&gWifiServiceContext, &kWifiServiceConfig); CHPP_DEBUG_ASSERT(gWifiServiceContext.service.handle); } } void chppDeregisterWifiService(struct ChppAppState *appContext) { // TODO UNUSED_VAR(appContext); }