/* * Copyright (C) 2024 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 "transport_util.h" #include #include #include #include #include #include #include #include "chpp/app.h" #include "chpp/common/discovery.h" #include "chpp/common/gnss.h" #include "chpp/common/gnss_types.h" #include "chpp/common/standard_uuids.h" #include "chpp/common/wifi.h" #include "chpp/common/wifi_types.h" #include "chpp/common/wwan.h" #include "chpp/crc.h" #include "chpp/macros.h" #include "chpp/memory.h" #include "chpp/platform/platform_link.h" #include "chpp/platform/utils.h" #include "chpp/services/discovery.h" #include "chpp/services/loopback.h" #include "chpp/transport.h" #include "chre/pal/wwan.h" namespace chpp::test { /** * Wait for chppTransportDoWork() to finish after it is notified by * chppEnqueueTxPacket to run. */ void WaitForTransport(struct ChppTransportState *transportContext) { // Start sending data out. cycleSendThread(); // Wait for data to be received and processed. std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Should have reset loc and length for next packet / datagram EXPECT_EQ(transportContext->rxStatus.locInDatagram, 0); EXPECT_EQ(transportContext->rxDatagram.length, 0); } /** * Validates a ChppTestResponse. Since the error field within the * ChppAppHeader struct is optional (and not used for common services), this * function returns the error field to be checked if desired, depending on the * service. * * @param buf Buffer containing response. * @param ackSeq Ack sequence to be verified. * @param handle Handle number to be verified * @param transactionID Transaction ID to be verified. * * @return The error field within the ChppAppHeader struct that is used by some * but not all services. */ uint8_t validateChppTestResponse(void *buf, uint8_t ackSeq, uint8_t handle, uint8_t transactionID) { struct ChppTestResponse *response = (ChppTestResponse *)buf; // Check preamble EXPECT_EQ(response->preamble0, kChppPreamble0); EXPECT_EQ(response->preamble1, kChppPreamble1); // Check response transport headers EXPECT_EQ(response->transportHeader.packetCode, CHPP_TRANSPORT_ERROR_NONE); EXPECT_EQ(response->transportHeader.ackSeq, ackSeq); // Check response app headers EXPECT_EQ(response->appHeader.handle, handle); EXPECT_EQ(response->appHeader.type, CHPP_MESSAGE_TYPE_SERVICE_RESPONSE); EXPECT_EQ(response->appHeader.transaction, transactionID); // Return optional response error to be checked if desired return response->appHeader.error; } /** * Aborts a packet and validates state. * * @param transportcontext Maintains status for each transport layer instance. */ void endAndValidatePacket(struct ChppTransportState *transportContext) { chppRxPacketCompleteCb(transportContext); EXPECT_EQ(transportContext->rxStatus.state, CHPP_STATE_PREAMBLE); EXPECT_EQ(transportContext->rxStatus.locInDatagram, 0); EXPECT_EQ(transportContext->rxDatagram.length, 0); } /** * Adds a preamble to a certain location in a buffer, and increases the location * accordingly, to account for the length of the added preamble. * * @param buf Buffer. * @param location Location to add the preamble, which its value will be * increased accordingly. */ void addPreambleToBuf(uint8_t *buf, size_t *location) { buf[(*location)++] = kChppPreamble0; buf[(*location)++] = kChppPreamble1; } /** * Adds a transport header (with default values) to a certain location in a * buffer, and increases the location accordingly, to account for the length of * the added transport header. * * @param buf Buffer. * @param location Location to add the transport header, which its value will be * increased accordingly. * * @return Pointer to the added transport header (e.g. to modify its fields). */ ChppTransportHeader *addTransportHeaderToBuf(uint8_t *buf, size_t *location) { size_t oldLoc = *location; // Default values for initial, minimum size request packet ChppTransportHeader transHeader = {}; transHeader.flags = CHPP_TRANSPORT_FLAG_FINISHED_DATAGRAM; transHeader.packetCode = CHPP_TRANSPORT_ERROR_NONE; transHeader.ackSeq = 1; transHeader.seq = 0; transHeader.length = sizeof(ChppAppHeader); transHeader.reserved = 0; memcpy(&buf[*location], &transHeader, sizeof(transHeader)); *location += sizeof(transHeader); return (ChppTransportHeader *)&buf[oldLoc]; } /** * Adds an app header (with default values) to a certain location in a buffer, * and increases the location accordingly, to account for the length of the * added app header. * * @param buf Buffer. * @param location Location to add the app header, which its value will be * increased accordingly. * * @return Pointer to the added app header (e.g. to modify its fields). */ ChppAppHeader *addAppHeaderToBuf(uint8_t *buf, size_t *location) { size_t oldLoc = *location; // Default values - to be updated later as necessary ChppAppHeader appHeader = {}; appHeader.handle = CHPP_HANDLE_NEGOTIATED_RANGE_START; appHeader.type = CHPP_MESSAGE_TYPE_CLIENT_REQUEST; appHeader.transaction = 0; appHeader.error = CHPP_APP_ERROR_NONE; appHeader.command = 0; memcpy(&buf[*location], &appHeader, sizeof(appHeader)); *location += sizeof(appHeader); return (ChppAppHeader *)&buf[oldLoc]; } /** * Adds a transport footer to a certain location in a buffer, and increases the * location accordingly, to account for the length of the added preamble. * * @param buf Buffer. * @param location Location to add the footer. The value of location will be * increased accordingly. * */ void addTransportFooterToBuf(uint8_t *buf, size_t *location) { uint32_t *checksum = (uint32_t *)&buf[*location]; *checksum = chppCrc32(0, &buf[CHPP_PREAMBLE_LEN_BYTES], *location - CHPP_PREAMBLE_LEN_BYTES); *location += sizeof(ChppTransportFooter); } /** * Opens a service and checks to make sure it was opened correctly. * * @param transportContext Transport layer context. * @param buf Buffer. * @param ackSeq Ack sequence of the packet to be sent out * @param seq Sequence number of the packet to be sent out. * @param handle Handle of the service to be opened. * @param transactionID Transaction ID for the open request. * @param command Open command. */ void openService(ChppTransportState *transportContext, uint8_t *buf, uint8_t ackSeq, uint8_t seq, uint8_t handle, uint8_t transactionID, uint16_t command, struct ChppLinuxLinkState &chppLinuxLinkContext) { size_t len = 0; addPreambleToBuf(buf, &len); ChppTransportHeader *transHeader = addTransportHeaderToBuf(buf, &len); transHeader->ackSeq = ackSeq; transHeader->seq = seq; ChppAppHeader *appHeader = addAppHeaderToBuf(buf, &len); appHeader->handle = handle; appHeader->transaction = transactionID; appHeader->command = command; addTransportFooterToBuf(buf, &len); // Send header + payload (if any) + footer EXPECT_TRUE(chppRxDataCb(transportContext, buf, len)); // Check for correct state uint8_t nextSeq = transHeader->seq + 1; EXPECT_EQ(transportContext->rxStatus.expectedSeq, nextSeq); EXPECT_EQ(transportContext->rxStatus.state, CHPP_STATE_PREAMBLE); // Wait for response WaitForTransport(transportContext); // Validate common response fields EXPECT_EQ(validateChppTestResponse(chppLinuxLinkContext.buf, nextSeq, handle, transactionID), CHPP_APP_ERROR_NONE); // Check response length EXPECT_EQ(sizeof(ChppTestResponse), CHPP_PREAMBLE_LEN_BYTES + sizeof(ChppTransportHeader) + sizeof(ChppAppHeader)); EXPECT_EQ(transportContext->linkBufferSize, sizeof(ChppTestResponse) + sizeof(ChppTransportFooter)); } /** * Sends a command to a service and checks for errors. * * @param transportContext Transport layer context. * @param buf Buffer. * @param ackSeq Ack sequence of the packet to be sent out * @param seq Sequence number of the packet to be sent out. * @param handle Handle of the service to be opened. * @param transactionID Transaction ID for the open request. * @param command Command to be sent. */ void sendCommandToService(ChppTransportState *transportContext, uint8_t *buf, uint8_t ackSeq, uint8_t seq, uint8_t handle, uint8_t transactionID, uint16_t command, struct ChppLinuxLinkState &chppLinuxLinkContext) { size_t len = 0; addPreambleToBuf(buf, &len); ChppTransportHeader *transHeader = addTransportHeaderToBuf(buf, &len); transHeader->ackSeq = ackSeq; transHeader->seq = seq; ChppAppHeader *appHeader = addAppHeaderToBuf(buf, &len); appHeader->handle = handle; appHeader->transaction = transactionID; appHeader->command = command; addTransportFooterToBuf(buf, &len); // Send header + payload (if any) + footer EXPECT_TRUE(chppRxDataCb(transportContext, buf, len)); // Check for correct state uint8_t nextSeq = transHeader->seq + 1; EXPECT_EQ(transportContext->rxStatus.expectedSeq, nextSeq); EXPECT_EQ(transportContext->rxStatus.state, CHPP_STATE_PREAMBLE); // Wait for response WaitForTransport(transportContext); // Validate common response fields EXPECT_EQ(validateChppTestResponse(chppLinuxLinkContext.buf, nextSeq, handle, transactionID), CHPP_APP_ERROR_NONE); } /** * Find service handle by name. * * @param appContext App context. * @param name Service name. * @param handle Output service handle if found. * * @return True if service found, false otherwise. */ bool findServiceHandle(ChppAppState *appContext, const char *name, uint8_t *handle) { for (uint8_t i = 0; i < appContext->registeredServiceCount; i++) { if (0 == strcmp(appContext->registeredServices[i]->descriptor.name, name)) { *handle = appContext->registeredServiceStates[i]->handle; return true; } } return false; } } // namespace chpp::test