diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index f59a8984..5a93ed0f 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -977,7 +977,9 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) { // forward. Edge mode observes verified evidence on the receive path instead, // so repeat off and other forwarding filters do not hide a single upstream // path from a node at the edge of the network. +#if !defined(PORTABLE_MQTT_OBSERVER) if (!clock_sync_mesh_edge_enabled) recordAcceptedFloodClockSample(packet); +#endif #endif return true; } @@ -2489,12 +2491,14 @@ void MyMesh::onAdvertRecv(mesh::Packet *packet, const mesh::Identity &id, uint32 // Mesh calls this hook only after verifying the advert's Ed25519 signature. // Edge mode observes it here rather than in allowPacketForward(), because // forwarding can be disabled on a receive-only edge node. +#if !defined(PORTABLE_MQTT_OBSERVER) if (clock_sync_mesh_edge_enabled && isClockSyncCollectionActive()) { uint8_t source_id[4]; mesh::Utils::sha256(source_id, sizeof(source_id), id.pub_key, PUB_KEY_SIZE); recordClockSyncSample(mesh::CLOCK_SYNC_SAMPLE_SOURCE_SIGNED_ADVERT, source_id, timestamp, packet); } +#endif // if this a zero hop advert (and not via 'Share'), add it to neighbours if (packet->getPathHashCount() == 0 && !isShare(packet)) { @@ -2506,6 +2510,7 @@ void MyMesh::onAdvertRecv(mesh::Packet *packet, const mesh::Identity &id, uint32 } void MyMesh::onGroupPacketRecv(mesh::Packet* packet) { +#if !defined(PORTABLE_MQTT_OBSERVER) // The base Mesh calls this for every unseen, structurally valid group packet // before the forwarding decision. Public-channel decryption below also // verifies its MAC, so unrelated or forged channel packets are ignored. @@ -2513,6 +2518,9 @@ void MyMesh::onGroupPacketRecv(mesh::Packet* packet) { && packet->getPayloadType() == PAYLOAD_TYPE_GRP_TXT) { recordPublicChannelClockSample(packet); } +#else + (void)packet; +#endif } void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret, @@ -3090,7 +3098,9 @@ void MyMesh::begin(FILESYSTEM *fs) { #endif loadFloodChannelScopeRequirements(); loadFloodGroupModeration(); +#if !defined(PORTABLE_MQTT_OBSERVER) loadClockSyncPrefs(); +#endif #endif // establish default-scope @@ -8743,6 +8753,8 @@ void MyMesh::deleteFloodGroupModeration(const char* args, char* reply) { } } +#if !defined(PORTABLE_MQTT_OBSERVER) + void MyMesh::loadClockSyncPrefs() { clock_sync_mesh_enabled = CLOCK_SYNC_MESH_DEFAULT_ENABLED != 0; clock_sync_mesh_edge_enabled = CLOCK_SYNC_MESH_EDGE_DEFAULT_ENABLED != 0; @@ -9379,6 +9391,20 @@ void MyMesh::formatClockSyncStatus(const char* args, char* reply, size_t reply_l } } +#else + +// Portable MQTT observers use their bridge's NTP source. Omitting the mesh +// consensus implementation keeps these legacy-slot images update-compatible; +// FULL MQTT images retain both NTP and mesh clock synchronization. +static const char* clockSyncMeshSuppressionName(uint8_t source) { + (void)source; + return "unavailable"; +} + +void MyMesh::onManualClockSet() {} + +#endif + void MyMesh::formatStatsReply(char *reply) { StatsFormatHelper::formatCoreStats(reply, board, *_ms, _err_flags, _mgr); } diff --git a/src/helpers/ESP32TrueRandom.cpp b/src/helpers/ESP32TrueRandom.cpp index ab724535..0c95acb9 100644 --- a/src/helpers/ESP32TrueRandom.cpp +++ b/src/helpers/ESP32TrueRandom.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "IdentityGeneration.h" @@ -22,7 +23,12 @@ enum TrueRandomState : uint8_t { TRUE_RANDOM_DISCARDED }; -uint8_t true_random_pool[TRUE_RANDOM_POOL_SIZE]; +// Keep the short-lived startup pool on the heap. Classic ESP32 has a much +// smaller link-time DRAM window than its runtime heap, and retaining this +// buffer in .bss can prevent otherwise valid FULL bridge images from linking. +// The allocation happens during Arduino's early init hook and is securely +// erased and released as soon as the persisted/new identity is ready. +uint8_t* true_random_pool = NULL; size_t true_random_offset = 0; TrueRandomState true_random_state = TRUE_RANDOM_UNINITIALIZED; @@ -49,11 +55,12 @@ bool tryMixESP32TrueRandom(uint8_t* dest, size_t size) { SemaphoreHandle_t mutex = getTrueRandomMutex(); if (mutex == NULL || xSemaphoreTake(mutex, portMAX_DELAY) != pdTRUE) return false; - const bool valid_offset = true_random_offset <= sizeof(true_random_pool); + const bool valid_offset = true_random_offset <= TRUE_RANDOM_POOL_SIZE; const size_t available = valid_offset - ? sizeof(true_random_pool) - true_random_offset + ? TRUE_RANDOM_POOL_SIZE - true_random_offset : 0; - if (true_random_state != TRUE_RANDOM_READY || size > available) { + if (true_random_state != TRUE_RANDOM_READY || true_random_pool == NULL + || size > available) { xSemaphoreGive(mutex); return false; } @@ -81,10 +88,18 @@ void initializeESP32TrueRandom() { return; } + true_random_pool = static_cast(malloc(TRUE_RANDOM_POOL_SIZE)); + if (true_random_pool == NULL) { + true_random_state = TRUE_RANDOM_DISCARDED; + xSemaphoreGive(mutex); + esp_restart(); + return; + } + // ESP-IDF guarantees true RNG output while this SAR ADC entropy source is // enabled. Arduino's init hook below runs before variant and board setup. bootloader_random_enable(); - esp_fill_random(true_random_pool, sizeof(true_random_pool)); + esp_fill_random(true_random_pool, TRUE_RANDOM_POOL_SIZE); bootloader_random_disable(); true_random_offset = 0; @@ -105,14 +120,22 @@ void mixESP32TrueRandom(uint8_t* dest, size_t size) { void discardESP32TrueRandom() { SemaphoreHandle_t mutex = getTrueRandomMutex(); if (mutex == NULL || xSemaphoreTake(mutex, portMAX_DELAY) != pdTRUE) { - mbedtls_platform_zeroize(true_random_pool, sizeof(true_random_pool)); - true_random_offset = sizeof(true_random_pool); + if (true_random_pool != NULL) { + mbedtls_platform_zeroize(true_random_pool, TRUE_RANDOM_POOL_SIZE); + free(true_random_pool); + true_random_pool = NULL; + } + true_random_offset = TRUE_RANDOM_POOL_SIZE; true_random_state = TRUE_RANDOM_DISCARDED; return; } - mbedtls_platform_zeroize(true_random_pool, sizeof(true_random_pool)); - true_random_offset = sizeof(true_random_pool); + if (true_random_pool != NULL) { + mbedtls_platform_zeroize(true_random_pool, TRUE_RANDOM_POOL_SIZE); + free(true_random_pool); + true_random_pool = NULL; + } + true_random_offset = TRUE_RANDOM_POOL_SIZE; true_random_state = TRUE_RANDOM_DISCARDED; xSemaphoreGive(mutex); }