| /* |
| * 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 <gtest/gtest.h> |
| #include <stddef.h> |
| |
| #include <string.h> |
| |
| #include "chpp/common/wwan_types.h" |
| #include "chpp/memory.h" |
| |
| namespace { |
| |
| // clang-format off |
| const chreWwanCellInfo kChreCells[] = { |
| { |
| .timeStamp = 1234, |
| .cellInfoType = CHRE_WWAN_CELL_INFO_TYPE_LTE, |
| .timeStampType = CHRE_WWAN_CELL_TIMESTAMP_TYPE_MODEM, |
| .registered = 1, |
| .reserved = 111, // ignored |
| .CellInfo = { |
| .lte = { |
| .cellIdentityLte = { |
| .mcc = 777, |
| .mnc = 888, |
| .ci = 4321, |
| .pci = 333, |
| .tac = 9876, |
| .earfcn = 5432, |
| }, |
| .signalStrengthLte = { |
| .signalStrength = 27, |
| .rsrp = 96, |
| .rsrq = 18, |
| .rssnr = 157, |
| .cqi = 13, |
| .timingAdvance = INT32_MAX, |
| } |
| } |
| } |
| }, |
| { |
| .timeStamp = 1235, |
| .cellInfoType = CHRE_WWAN_CELL_INFO_TYPE_WCDMA, |
| .timeStampType = CHRE_WWAN_CELL_TIMESTAMP_TYPE_ANTENNA, |
| .registered = 0, |
| .CellInfo = { |
| .wcdma = { |
| .cellIdentityWcdma = { |
| .mcc = 123, |
| .mnc = 456, |
| .lac = 789, |
| .cid = 012, |
| .psc = 345, |
| .uarfcn = 678, |
| }, |
| .signalStrengthWcdma = { |
| .signalStrength = 99, |
| .bitErrorRate = INT32_MAX, |
| } |
| } |
| } |
| }, |
| }; |
| const chreWwanCellInfoResult kChreResultOneCell = { |
| .errorCode = 0, |
| .cellInfoCount = 1, |
| .cells = kChreCells, |
| }; |
| const chreWwanCellInfoResult kChreResultTwoCell = { |
| .errorCode = 0, |
| .cellInfoCount = 2, |
| .cells = kChreCells, |
| }; |
| // clang-format on |
| |
| void compareCellInfo(const chreWwanCellInfo *chre, |
| const ChppWwanCellInfo *chppIn) { |
| // Local variable needed to avoid unaligned memory access. |
| ChppWwanCellInfo chppLocal; |
| memcpy(&chppLocal, chppIn, sizeof(ChppWwanCellInfo)); |
| const ChppWwanCellInfo *chpp = &chppLocal; |
| |
| EXPECT_EQ(chpp->timeStamp, chre->timeStamp); |
| EXPECT_EQ(chpp->cellInfoType, chre->cellInfoType); |
| EXPECT_EQ(chpp->timeStampType, chre->timeStampType); |
| EXPECT_EQ(chpp->registered, chre->registered); |
| |
| switch (chpp->cellInfoType) { |
| case CHRE_WWAN_CELL_INFO_TYPE_LTE: |
| EXPECT_EQ(chpp->CellInfo.lte.cellIdentityLte.mcc, |
| chre->CellInfo.lte.cellIdentityLte.mcc); |
| EXPECT_EQ(chpp->CellInfo.lte.cellIdentityLte.mnc, |
| chre->CellInfo.lte.cellIdentityLte.mnc); |
| EXPECT_EQ(chpp->CellInfo.lte.cellIdentityLte.ci, |
| chre->CellInfo.lte.cellIdentityLte.ci); |
| EXPECT_EQ(chpp->CellInfo.lte.cellIdentityLte.pci, |
| chre->CellInfo.lte.cellIdentityLte.pci); |
| EXPECT_EQ(chpp->CellInfo.lte.cellIdentityLte.tac, |
| chre->CellInfo.lte.cellIdentityLte.tac); |
| EXPECT_EQ(chpp->CellInfo.lte.cellIdentityLte.earfcn, |
| chre->CellInfo.lte.cellIdentityLte.earfcn); |
| |
| EXPECT_EQ(chpp->CellInfo.lte.signalStrengthLte.signalStrength, |
| chre->CellInfo.lte.signalStrengthLte.signalStrength); |
| EXPECT_EQ(chpp->CellInfo.lte.signalStrengthLte.rsrp, |
| chre->CellInfo.lte.signalStrengthLte.rsrp); |
| EXPECT_EQ(chpp->CellInfo.lte.signalStrengthLte.rsrq, |
| chre->CellInfo.lte.signalStrengthLte.rsrq); |
| EXPECT_EQ(chpp->CellInfo.lte.signalStrengthLte.rssnr, |
| chre->CellInfo.lte.signalStrengthLte.rssnr); |
| EXPECT_EQ(chpp->CellInfo.lte.signalStrengthLte.cqi, |
| chre->CellInfo.lte.signalStrengthLte.cqi); |
| EXPECT_EQ(chpp->CellInfo.lte.signalStrengthLte.timingAdvance, |
| chre->CellInfo.lte.signalStrengthLte.timingAdvance); |
| break; |
| |
| case CHRE_WWAN_CELL_INFO_TYPE_WCDMA: |
| EXPECT_EQ(chpp->CellInfo.wcdma.cellIdentityWcdma.mcc, |
| chre->CellInfo.wcdma.cellIdentityWcdma.mcc); |
| EXPECT_EQ(chpp->CellInfo.wcdma.cellIdentityWcdma.mnc, |
| chre->CellInfo.wcdma.cellIdentityWcdma.mnc); |
| EXPECT_EQ(chpp->CellInfo.wcdma.cellIdentityWcdma.lac, |
| chre->CellInfo.wcdma.cellIdentityWcdma.lac); |
| EXPECT_EQ(chpp->CellInfo.wcdma.cellIdentityWcdma.cid, |
| chre->CellInfo.wcdma.cellIdentityWcdma.cid); |
| EXPECT_EQ(chpp->CellInfo.wcdma.cellIdentityWcdma.psc, |
| chre->CellInfo.wcdma.cellIdentityWcdma.psc); |
| EXPECT_EQ(chpp->CellInfo.wcdma.cellIdentityWcdma.uarfcn, |
| chre->CellInfo.wcdma.cellIdentityWcdma.uarfcn); |
| |
| EXPECT_EQ(chpp->CellInfo.wcdma.signalStrengthWcdma.signalStrength, |
| chre->CellInfo.wcdma.signalStrengthWcdma.signalStrength); |
| EXPECT_EQ(chpp->CellInfo.wcdma.signalStrengthWcdma.bitErrorRate, |
| chre->CellInfo.wcdma.signalStrengthWcdma.bitErrorRate); |
| break; |
| |
| default: |
| // Other types not supported yet |
| ASSERT_TRUE(false); |
| } |
| } |
| |
| //! Test for correct handling of a malformed ChppWwanCellInfoResult (e.g. short |
| //! payload, invalid offset/length) |
| void testMalformedCellInfoResultDecoding(struct ChppWwanCellInfoResult *chpp, |
| size_t inputSize) { |
| chreWwanCellInfoResult *chreMalformed; |
| |
| inputSize--; |
| chreMalformed = chppWwanCellInfoResultToChre(chpp, inputSize); |
| EXPECT_EQ(chreMalformed, nullptr); |
| inputSize++; |
| |
| chpp->cells.offset++; |
| chreMalformed = chppWwanCellInfoResultToChre(chpp, inputSize); |
| EXPECT_EQ(chreMalformed, nullptr); |
| chpp->cells.offset--; |
| |
| chpp->cells.length++; |
| chreMalformed = chppWwanCellInfoResultToChre(chpp, inputSize); |
| EXPECT_EQ(chreMalformed, nullptr); |
| chpp->cells.length--; |
| |
| chpp->cellInfoCount++; |
| chreMalformed = chppWwanCellInfoResultToChre(chpp, inputSize); |
| EXPECT_EQ(chreMalformed, nullptr); |
| chpp->cellInfoCount--; |
| |
| chpp->cellInfoCount--; |
| chreMalformed = chppWwanCellInfoResultToChre(chpp, inputSize); |
| EXPECT_EQ(chreMalformed, nullptr); |
| chpp->cellInfoCount++; |
| } |
| |
| TEST(WwanConvert, EncodeErrorCode) { |
| const chreWwanCellInfoResult chreResult = { |
| .version = 200, // ignored |
| .errorCode = 2, |
| .cellInfoCount = 0, |
| .reserved = 3, // ignored |
| .cookie = (void *)-1, // ignored |
| .cells = nullptr, |
| }; |
| |
| ChppWwanCellInfoResultWithHeader *chppWithHeader = nullptr; |
| size_t outputSize = 999; |
| bool result = |
| chppWwanCellInfoResultFromChre(&chreResult, &chppWithHeader, &outputSize); |
| ASSERT_TRUE(result); |
| ASSERT_NE(chppWithHeader, nullptr); |
| EXPECT_EQ(outputSize, sizeof(ChppWwanCellInfoResultWithHeader)); |
| |
| ChppWwanCellInfoResult *chpp = &chppWithHeader->payload; |
| EXPECT_EQ(chpp->version, CHRE_WWAN_CELL_INFO_RESULT_VERSION); |
| EXPECT_EQ(chpp->errorCode, chreResult.errorCode); |
| EXPECT_EQ(chpp->cellInfoCount, chreResult.cellInfoCount); |
| EXPECT_EQ(chpp->reserved, 0); |
| EXPECT_EQ(chpp->cookie, 0u); |
| EXPECT_EQ(chpp->cells.offset, 0); |
| EXPECT_EQ(chpp->cells.length, 0); |
| |
| chppFree(chppWithHeader); |
| } |
| |
| TEST(WwanConvert, DecodeErrorCode) { |
| const ChppWwanCellInfoResult chpp = { |
| .version = 200, // ignored |
| .errorCode = 2, |
| .cellInfoCount = 0, |
| .reserved = 3, // ignored |
| .cookie = 100, // ignored |
| .cells.offset = 0, |
| .cells.length = 0, |
| }; |
| |
| size_t outputSize = sizeof(struct ChppWwanCellInfoResult); |
| chreWwanCellInfoResult *chre = |
| chppWwanCellInfoResultToChre(&chpp, outputSize); |
| ASSERT_NE(chre, nullptr); |
| |
| EXPECT_EQ(chre->version, CHRE_WWAN_CELL_INFO_RESULT_VERSION); |
| EXPECT_EQ(chre->errorCode, chpp.errorCode); |
| EXPECT_EQ(chre->cellInfoCount, chpp.cellInfoCount); |
| EXPECT_EQ(chre->reserved, 0); |
| EXPECT_EQ(chre->cookie, (void *)0); |
| |
| // Handling of short payload |
| chreWwanCellInfoResult *chreShort = |
| chppWwanCellInfoResultToChre(&chpp, outputSize - 1); |
| ASSERT_EQ(chreShort, nullptr); |
| |
| chppFree(chre); |
| } |
| |
| TEST(WwanConvert, EncodeOneCell) { |
| ChppWwanCellInfoResultWithHeader *chppWithHeader = nullptr; |
| size_t outputSize = 999; |
| bool result = chppWwanCellInfoResultFromChre(&kChreResultOneCell, |
| &chppWithHeader, &outputSize); |
| ASSERT_TRUE(result); |
| ASSERT_NE(chppWithHeader, nullptr); |
| EXPECT_EQ(outputSize, sizeof(ChppWwanCellInfoResultWithHeader) + |
| sizeof(ChppWwanCellInfo)); |
| |
| ChppWwanCellInfoResult *chpp = &chppWithHeader->payload; |
| EXPECT_EQ(chpp->errorCode, kChreResultOneCell.errorCode); |
| EXPECT_EQ(chpp->cellInfoCount, kChreResultOneCell.cellInfoCount); |
| EXPECT_EQ(chpp->cells.offset, sizeof(ChppWwanCellInfoResult)); |
| EXPECT_EQ(chpp->cells.length, sizeof(ChppWwanCellInfo)); |
| |
| ChppWwanCellInfo *chppCell = |
| (ChppWwanCellInfo *)((uint8_t *)chpp + chpp->cells.offset); |
| EXPECT_EQ(chppCell->reserved, 0); |
| compareCellInfo(&kChreCells[0], chppCell); |
| |
| chppFree(chppWithHeader); |
| } |
| |
| TEST(WwanConvert, EncodeDecodeOneCell) { |
| ChppWwanCellInfoResultWithHeader *chppWithHeader; |
| size_t outputSize; |
| bool result = chppWwanCellInfoResultFromChre(&kChreResultOneCell, |
| &chppWithHeader, &outputSize); |
| ASSERT_TRUE(result); |
| ASSERT_NE(chppWithHeader, nullptr); |
| |
| ChppWwanCellInfoResult *chpp = &chppWithHeader->payload; |
| ChppWwanCellInfo *chppCell = |
| (ChppWwanCellInfo *)((uint8_t *)chpp + chpp->cells.offset); |
| |
| chpp->version = 100; // ignored |
| chpp->reserved = 10; // ignored |
| chpp->cookie = -10; // ignored |
| |
| size_t inputSize = outputSize - sizeof(struct ChppAppHeader); |
| |
| chreWwanCellInfoResult *chre = chppWwanCellInfoResultToChre(chpp, inputSize); |
| ASSERT_NE(chre, nullptr); |
| |
| EXPECT_EQ(chre->version, CHRE_WWAN_CELL_INFO_RESULT_VERSION); |
| EXPECT_EQ(chre->reserved, 0); |
| EXPECT_EQ(chre->cookie, (void *)0); |
| |
| EXPECT_EQ(chre->errorCode, chpp->errorCode); |
| EXPECT_EQ(chre->errorCode, kChreResultOneCell.errorCode); |
| EXPECT_EQ(chre->cellInfoCount, chpp->cellInfoCount); |
| EXPECT_EQ(chre->cellInfoCount, kChreResultOneCell.cellInfoCount); |
| |
| EXPECT_EQ(chre->cells[0].reserved, 0); |
| compareCellInfo(&kChreCells[0], chppCell); |
| compareCellInfo(&chre->cells[0], chppCell); |
| |
| testMalformedCellInfoResultDecoding(chpp, inputSize); |
| |
| chppFree(chppWithHeader); |
| chppFree(chre); |
| } |
| |
| TEST(WwanConvert, EncodeTwoCells) { |
| ChppWwanCellInfoResultWithHeader *chppWithHeader = nullptr; |
| size_t outputSize = 999; |
| bool result = chppWwanCellInfoResultFromChre(&kChreResultTwoCell, |
| &chppWithHeader, &outputSize); |
| ASSERT_TRUE(result); |
| ASSERT_NE(chppWithHeader, nullptr); |
| EXPECT_EQ(outputSize, sizeof(ChppWwanCellInfoResultWithHeader) + |
| 2 * sizeof(ChppWwanCellInfo)); |
| |
| ChppWwanCellInfoResult *chpp = &chppWithHeader->payload; |
| EXPECT_EQ(chpp->errorCode, kChreResultTwoCell.errorCode); |
| EXPECT_EQ(chpp->cellInfoCount, kChreResultTwoCell.cellInfoCount); |
| EXPECT_EQ(chpp->cells.offset, sizeof(ChppWwanCellInfoResult)); |
| EXPECT_EQ(chpp->cells.length, 2 * sizeof(ChppWwanCellInfo)); |
| |
| ChppWwanCellInfo *chppCells = |
| (ChppWwanCellInfo *)((uint8_t *)chpp + chpp->cells.offset); |
| EXPECT_EQ(chppCells[0].reserved, 0); |
| EXPECT_EQ(chppCells[1].reserved, 0); |
| compareCellInfo(&kChreCells[0], &chppCells[0]); |
| compareCellInfo(&kChreCells[1], &chppCells[1]); |
| |
| // Ensure unused bytes in the union are zeroed out |
| uint8_t *pastEnd = |
| (uint8_t *)&chppCells[1].CellInfo.wcdma.signalStrengthWcdma.bitErrorRate + |
| sizeof(chppCells[1].CellInfo.wcdma.signalStrengthWcdma.bitErrorRate); |
| size_t sizePastEnd = sizeof(chreWwanCellInfo::chreWwanCellInfoPerRat) - |
| sizeof(chreWwanCellInfoWcdma); |
| uint8_t zeros[sizePastEnd]; |
| memset(zeros, 0, sizePastEnd); |
| EXPECT_EQ(memcmp(pastEnd, zeros, sizeof(zeros)), 0); |
| |
| chppFree(chppWithHeader); |
| } |
| |
| TEST(WwanConvert, EncodeDecodeTwoCells) { |
| ChppWwanCellInfoResultWithHeader *chppWithHeader; |
| size_t outputSize; |
| bool result = chppWwanCellInfoResultFromChre(&kChreResultTwoCell, |
| &chppWithHeader, &outputSize); |
| ASSERT_TRUE(result); |
| ASSERT_NE(chppWithHeader, nullptr); |
| |
| ChppWwanCellInfoResult *chpp = &chppWithHeader->payload; |
| ChppWwanCellInfo *chppCells = |
| (ChppWwanCellInfo *)((uint8_t *)chpp + chpp->cells.offset); |
| |
| chpp->version = 100; // ignored |
| chpp->reserved = 10; // ignored |
| chpp->cookie = -10; // ignored |
| |
| size_t inputSize = outputSize - sizeof(struct ChppAppHeader); |
| |
| chreWwanCellInfoResult *chre = chppWwanCellInfoResultToChre(chpp, inputSize); |
| ASSERT_NE(chre, nullptr); |
| |
| EXPECT_EQ(chre->version, CHRE_WWAN_CELL_INFO_RESULT_VERSION); |
| EXPECT_EQ(chre->reserved, 0); |
| EXPECT_EQ(chre->cookie, (void *)0); |
| |
| EXPECT_EQ(chre->errorCode, chpp->errorCode); |
| EXPECT_EQ(chpp->errorCode, kChreResultTwoCell.errorCode); |
| EXPECT_EQ(chre->cellInfoCount, chpp->cellInfoCount); |
| EXPECT_EQ(chpp->cellInfoCount, kChreResultTwoCell.cellInfoCount); |
| |
| EXPECT_EQ(chre->cells[0].reserved, 0); |
| compareCellInfo(&kChreCells[0], &chppCells[0]); |
| compareCellInfo(&chre->cells[0], &chppCells[0]); |
| |
| EXPECT_EQ(chre->cells[1].reserved, 0); |
| compareCellInfo(&kChreCells[1], &chppCells[1]); |
| compareCellInfo(&chre->cells[1], &chppCells[1]); |
| |
| testMalformedCellInfoResultDecoding(chpp, inputSize); |
| |
| chppFree(chppWithHeader); |
| chppFree(chre); |
| } |
| |
| } // namespace |