From 9403edeaafdd0e6da3579e29bc733474d6d3f84b Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Mon, 4 May 2026 11:52:58 +0200 Subject: [PATCH] [tcat][ble] Fix BLE advertisement contents after Commissioner disconnect (#12913) This fixes the issue observed in tests, that the BLE advertisement contents (flags) were not updated after a TCAT Commissioner disconnects. A unit test is added for BLE advertisement contents to validate the advertisement data changes. It also adds an explicit 'disconnect' CLI command to the TCAT expect tests, which wasn't tested before. --- src/core/radio/ble_secure.cpp | 13 +++++- .../scripts/expect/cli-tcat-decommission.exp | 3 ++ tests/unit/test_platform.cpp | 18 +++++--- tests/unit/test_platform.h | 12 +++++ tests/unit/test_tcat.cpp | 44 +++++++++++++++++++ 5 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/core/radio/ble_secure.cpp b/src/core/radio/ble_secure.cpp index ba66ed64b..3186f9509 100644 --- a/src/core/radio/ble_secure.cpp +++ b/src/core/radio/ble_secure.cpp @@ -196,10 +196,19 @@ Error BleSecure::NotifyAdvertisementChanged(void) uint16_t advertisementLen = 0; uint8_t *advertisementData = nullptr; - VerifyOrExit(mBleState == kAdvertising); + VerifyOrExit(mBleState != kStopped); SuccessOrExit(error = otPlatBleGetAdvertisementBuffer(&GetInstance(), &advertisementData)); SuccessOrExit(error = Get().GetAdvertisementData(advertisementLen, advertisementData)); - SuccessOrExit(error = otPlatBleGapAdvUpdateData(&GetInstance(), advertisementData, advertisementLen)); + + if (mBleState == kAdvertising) + { + SuccessOrExit(error = otPlatBleGapAdvUpdateData(&GetInstance(), advertisementData, advertisementLen)); + } + else + { + // Any other state: update buffered data for when advertising resumes. + SuccessOrExit(error = otPlatBleGapAdvSetData(&GetInstance(), advertisementData, advertisementLen)); + } exit: return error; diff --git a/tests/scripts/expect/cli-tcat-decommission.exp b/tests/scripts/expect/cli-tcat-decommission.exp index cfd5e589c..3825dac3c 100755 --- a/tests/scripts/expect/cli-tcat-decommission.exp +++ b/tests/scripts/expect/cli-tcat-decommission.exp @@ -53,6 +53,9 @@ send "thread start\n" expect_line "\tTYPE:\tRESPONSE_W_STATUS" expect_line "\tVALUE:\t0x00" +send "disconnect\n" +expect_line "Done" + dispose_tcat_client 1 switch_node 1 diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index 621dd0f81..d29e3748d 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -801,6 +801,10 @@ OT_TOOL_WEAK otPlatMcuPowerState otPlatGetMcuPowerState(otInstance *aInstance) { OT_TOOL_WEAK otError otPlatSetMcuPowerState(otInstance *aInstance, otPlatMcuPowerState aState) { return OT_ERROR_NONE; } #endif // OPENTHREAD_CONFIG_NCP_ENABLE_MCU_POWER_STATE_CONTROL #ifdef OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +uint8_t sPlatBleLastAdvSetData[OT_TCAT_ADVERTISEMENT_MAX_LEN]; +uint16_t sPlatBleLastAdvSetDataLen = 0; + otError otPlatBleEnable(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); @@ -875,17 +879,19 @@ bool otPlatBleSupportsMultiRadio(otInstance *aInstance) otError otPlatBleGapAdvSetData(otInstance *aInstance, uint8_t *aAdvertisementData, uint16_t aAdvertisementLen) { OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aAdvertisementData); - OT_UNUSED_VARIABLE(aAdvertisementLen); + if (aAdvertisementData == nullptr || aAdvertisementLen > OT_TCAT_ADVERTISEMENT_MAX_LEN) + { + return OT_ERROR_INVALID_ARGS; + } + memcpy(sPlatBleLastAdvSetData, aAdvertisementData, aAdvertisementLen); + sPlatBleLastAdvSetDataLen = aAdvertisementLen; + return OT_ERROR_NONE; } otError otPlatBleGapAdvUpdateData(otInstance *aInstance, uint8_t *aAdvertisementData, uint16_t aAdvertisementLen) { - OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aAdvertisementData); - OT_UNUSED_VARIABLE(aAdvertisementLen); - return OT_ERROR_NONE; + return otPlatBleGapAdvSetData(aInstance, aAdvertisementData, aAdvertisementLen); } #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE diff --git a/tests/unit/test_platform.h b/tests/unit/test_platform.h index 4eedd4edc..87904c214 100644 --- a/tests/unit/test_platform.h +++ b/tests/unit/test_platform.h @@ -57,4 +57,16 @@ ot::Instance *testInitAdditionalInstance(uint8_t id); #endif void testFreeInstance(otInstance *aInstance); +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#include +#ifdef __cplusplus +extern "C" { +#endif +extern uint8_t sPlatBleLastAdvSetData[OT_TCAT_ADVERTISEMENT_MAX_LEN]; +extern uint16_t sPlatBleLastAdvSetDataLen; +#ifdef __cplusplus +} +#endif +#endif + #endif // OT_UNIT_TEST_PLATFORM_H_ diff --git a/tests/unit/test_tcat.cpp b/tests/unit/test_tcat.cpp index 2c4acfd56..a6f8a7e16 100644 --- a/tests/unit/test_tcat.cpp +++ b/tests/unit/test_tcat.cpp @@ -36,6 +36,7 @@ #include #include "cli/cli_dataset.hpp" +#include "radio/ble_secure.hpp" #define OT_TCAT_X509_CERT \ "-----BEGIN CERTIFICATE-----\n" \ @@ -267,6 +268,8 @@ static Instance *TestInitInstanceTcat(void) memcpy(&sCommExtPanId, &kExtPanId, sizeof(sCommExtPanId)); memcpy(&sCommAuth, &kCommCert1AuthField, sizeof(sCommAuth)); memcpy(&sDeviceAuth, &kDeviceCert1AuthField, sizeof(sDeviceAuth)); + sPlatBleLastAdvSetDataLen = 0; + memset(sPlatBleLastAdvSetData, 0, OT_TCAT_ADVERTISEMENT_MAX_LEN); return instance; } @@ -336,6 +339,46 @@ void TestTcatConnectionAndCertAttributes(void) testFreeInstance(instance); } +void TestTcatAdvertisementUpdates(void) +{ + TestBleSecure ble; + Instance *instance = TestInitInstanceTcat(); + uint8_t advDataSnapshot[OT_TCAT_ADVERTISEMENT_MAX_LEN]; + uint16_t advDataSnapshotLen; + + VerifyOrQuit(sPlatBleLastAdvSetDataLen == 0, "Adv data should be unset before BleSecure start"); + + SuccessOrQuit(otBleSecureStart(instance, HandleBleSecureConnect, nullptr, true, &ble)); + SuccessOrQuit(otBleSecureTcatStart(instance, nullptr)); + + VerifyOrQuit(sPlatBleLastAdvSetDataLen > 0, "Adv data should be set after BleSecure start"); + advDataSnapshotLen = sPlatBleLastAdvSetDataLen; + memcpy(advDataSnapshot, sPlatBleLastAdvSetData, advDataSnapshotLen); + + otPlatBleGapOnConnected(instance, kConnectionId); + SuccessOrQuit(otBleSecureConnect(instance)); + + // BLE connect and initiating TLS does not change the adv data. + VerifyOrQuit(sPlatBleLastAdvSetDataLen == advDataSnapshotLen && + memcmp(sPlatBleLastAdvSetData, advDataSnapshot, advDataSnapshotLen) == 0, + "Adv data changed unexpectedly after BLE connect"); + advDataSnapshotLen = sPlatBleLastAdvSetDataLen; + memcpy(advDataSnapshot, sPlatBleLastAdvSetData, advDataSnapshotLen); + + // Commissioner sets dataset, then disconnects + instance->Get().SaveLocal(sPartialDataset); + otBleSecureDisconnect(instance); + + // Adv is changed due to the partial dataset now being advertised in the S flag. + VerifyOrQuit(sPlatBleLastAdvSetDataLen == advDataSnapshotLen, "Adv data length changed unexpectedly"); + VerifyOrQuit(memcmp(sPlatBleLastAdvSetData, advDataSnapshot, advDataSnapshotLen) != 0, + "Adv data did not change after disconnect, which it should due to S flag"); + + otBleSecureStop(instance); + + testFreeInstance(instance); +} + class UnitTester { private: @@ -834,6 +877,7 @@ int main(void) ot::MeshCoP::UnitTester::TestTcatCommissioner1AuthWithDeviceRequirements(); ot::MeshCoP::UnitTester::TestTcatCommissioner2AuthWithDeviceRequirements(); ot::MeshCoP::UnitTester::TestTcatCommissioner4AuthWithExistingPartialDataset(); + ot::MeshCoP::TestTcatAdvertisementUpdates(); printf("All tests passed\n"); #else printf("TCAT feature is not enabled\n");