From 7ea461e4430840b864440a734e6a0731023f3d09 Mon Sep 17 00:00:00 2001 From: pelgraine <140762863+pelgraine@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:28:58 +1100 Subject: [PATCH] MeshCore v1.18 batch 3: path length checks, trace offset, GPS clock wrap, UTF-8 advert names, BLE receive queue, search results 24, trace timeout --- examples/companion_radio/MyMesh.cpp | 5 +- src/Mesh.cpp | 8 ++- src/helpers/AdvertDataHelpers.cpp | 12 ++-- src/helpers/BaseChatMesh.h | 2 +- src/helpers/UTF8Helpers.h | 56 +++++++++++++++++++ src/helpers/esp32/SerialBLEInterface.cpp | 37 ++++++------ src/helpers/esp32/SerialBLEInterface.h | 14 +++-- .../sensors/EnvironmentSensorManager.cpp | 4 +- .../sensors/MicroNMEALocationProvider.h | 4 +- 9 files changed, 104 insertions(+), 38 deletions(-) create mode 100644 src/helpers/UTF8Helpers.h diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index c4755ef8..af4ee132 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2495,7 +2495,8 @@ void MyMesh::handleCmdFrame(size_t len) { } else if (cmd_frame[0] == CMD_SEND_RAW_DATA && len >= 6) { int i = 1; uint8_t path_len = cmd_frame[i++]; - if (path_len != OUT_PATH_UNKNOWN && i + mesh::Packet::getPathByteLenFor(path_len) + 4 <= len) { // minimum 4 byte payload + if (path_len != OUT_PATH_UNKNOWN && mesh::Packet::isValidPathLen(path_len) + && i + mesh::Packet::getPathByteLenFor(path_len) + 4 <= len) { // minimum 4 byte payload uint8_t *path = &cmd_frame[i]; i += mesh::Packet::getPathByteLenFor(path_len); auto pkt = createRawData(&cmd_frame[i], len - i); @@ -2762,7 +2763,7 @@ void MyMesh::handleCmdFrame(size_t len) { sendDirect(pkt, &cmd_frame[10], path_len); uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); - uint32_t est_timeout = calcDirectTimeoutMillisFor(t, path_len); + uint32_t est_timeout = calcDirectTimeoutMillisFor(t, path_len >> path_sz); out_frame[0] = RESP_CODE_SENT; out_frame[1] = 0; diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 9d3bf882..73866113 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -55,7 +55,9 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { uint8_t path_sz = flags & 0x03; // NEW v1.11+: lower 2 bits is path hash size uint8_t len = pkt->payload_len - i; - uint8_t offset = pkt->path_len << path_sz; + // path_len*entry_size can exceed 255 (path_len up to 63, entry_size up to 8); + // a uint8_t offset would wrap and steer the isHashMatch() read to the wrong place. + uint16_t offset = (uint16_t)pkt->path_len << path_sz; if (offset >= len) { // TRACE has reached end of given path onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len); } else if (self_id.isHashMatch(&pkt->payload[i + offset], 1 << path_sz) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) { @@ -160,6 +162,10 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) { if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH) { int k = 0; uint8_t path_len = data[k++]; + if (!Packet::isValidPathLen(path_len)) { + MESH_DEBUG_PRINTLN("%s PAYLOAD_TYPE_PATH, bad path_len: %u", getLogDateTime(), (uint32_t)path_len); + break; // reject bad encoding + } uint8_t* path = &data[k]; k += Packet::getPathByteLenFor(path_len); uint8_t extra_type = data[k++] & 0x0F; // upper 4 bits reserved for future use uint8_t* extra = &data[k]; diff --git a/src/helpers/AdvertDataHelpers.cpp b/src/helpers/AdvertDataHelpers.cpp index 0e05620e..6eff8501 100644 --- a/src/helpers/AdvertDataHelpers.cpp +++ b/src/helpers/AdvertDataHelpers.cpp @@ -1,4 +1,5 @@ #include +#include uint8_t AdvertDataBuilder::encodeTo(uint8_t app_data[]) { app_data[0] = _type; @@ -16,11 +17,12 @@ app_data[0] |= ADV_FEAT2_MASK; memcpy(&app_data[i], &_extra2, 2); i += 2; } - if (_name && *_name != 0) { - app_data[0] |= ADV_NAME_MASK; - const char* sp = _name; - while (*sp && i < MAX_ADVERT_DATA_SIZE) { - app_data[i++] = *sp++; + if (_name && *_name != 0) { + size_t name_len = mesh::validUtf8PrefixLength(_name, MAX_ADVERT_DATA_SIZE - i); + if (name_len > 0) { + app_data[0] |= ADV_NAME_MASK; + memcpy(&app_data[i], _name, name_len); + i += name_len; } } return i; diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 9db6a0a3..6294f363 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -9,7 +9,7 @@ #include "ContactInfo.h" -#define MAX_SEARCH_RESULTS 8 +#define MAX_SEARCH_RESULTS 24 #define MSG_SEND_FAILED 0 #define MSG_SEND_SENT_FLOOD 1 diff --git a/src/helpers/UTF8Helpers.h b/src/helpers/UTF8Helpers.h new file mode 100644 index 00000000..e06cf4a6 --- /dev/null +++ b/src/helpers/UTF8Helpers.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +namespace mesh { + +inline bool isUtf8Continuation(uint8_t byte) { + return (byte & 0xC0) == 0x80; +} + +inline size_t validUtf8PrefixLength(const char* text, size_t max_bytes) { + if (text == nullptr) return 0; + + size_t offset = 0; + while (text[offset] != '\0') { + const uint8_t first = static_cast(text[offset]); + size_t sequence_length = 0; + + if (first <= 0x7F) { + sequence_length = 1; + } else if (first >= 0xC2 && first <= 0xDF) { + sequence_length = 2; + } else if (first >= 0xE0 && first <= 0xEF) { + sequence_length = 3; + } else if (first >= 0xF0 && first <= 0xF4) { + sequence_length = 4; + } else { + break; + } + + if (offset + sequence_length > max_bytes) break; + + bool complete = true; + for (size_t i = 1; i < sequence_length; i++) { + if (text[offset + i] == '\0' || !isUtf8Continuation(static_cast(text[offset + i]))) { + complete = false; + break; + } + } + if (!complete) break; + + if (sequence_length == 3) { + const uint8_t second = static_cast(text[offset + 1]); + if ((first == 0xE0 && second < 0xA0) || (first == 0xED && second > 0x9F)) break; + } else if (sequence_length == 4) { + const uint8_t second = static_cast(text[offset + 1]); + if ((first == 0xF0 && second < 0x90) || (first == 0xF4 && second > 0x8F)) break; + } + + offset += sequence_length; + } + return offset; +} + +} // namespace mesh diff --git a/src/helpers/esp32/SerialBLEInterface.cpp b/src/helpers/esp32/SerialBLEInterface.cpp index 495a9823..b15fff43 100644 --- a/src/helpers/esp32/SerialBLEInterface.cpp +++ b/src/helpers/esp32/SerialBLEInterface.cpp @@ -228,11 +228,10 @@ void SerialBLEInterface::onWrite(BLECharacteristic* pCharacteristic, esp_ble_gat memcpy(&_rx_buf[_rx_len], rxValue + 2, n); _rx_len += n; if (tag == SLICE_TAG_LAST || tag == SLICE_TAG_SINGLE) { - if (recv_queue_len < FRAME_QUEUE_SIZE) { - recv_queue[recv_queue_len].len = _rx_len; - memcpy(recv_queue[recv_queue_len].buf, _rx_buf, _rx_len); - recv_queue_len++; - } else { + Frame frame; + frame.len = _rx_len; + memcpy(frame.buf, _rx_buf, _rx_len); + if (xQueueSend(recv_queue, &frame, 0) != pdTRUE) { BLE_DEBUG_PRINTLN("ERROR: onWrite(), recv_queue is full! (sliced)"); } _rx_len = -1; @@ -242,12 +241,14 @@ void SerialBLEInterface::onWrite(BLECharacteristic* pCharacteristic, esp_ble_gat #endif if (len > MAX_FRAME_SIZE) { BLE_DEBUG_PRINTLN("ERROR: onWrite(), frame too big, len=%d", len); - } else if (recv_queue_len >= FRAME_QUEUE_SIZE) { - BLE_DEBUG_PRINTLN("ERROR: onWrite(), recv_queue is full!"); } else { - recv_queue[recv_queue_len].len = len; - memcpy(recv_queue[recv_queue_len].buf, rxValue, len); - recv_queue_len++; + Frame frame; + frame.len = len; + memcpy(frame.buf, rxValue, len); + + if (xQueueSend(recv_queue, &frame, 0) != pdTRUE) { + BLE_DEBUG_PRINTLN("ERROR: onWrite(), recv_queue is full!"); + } } } @@ -377,17 +378,11 @@ size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) { #endif } - if (recv_queue_len > 0) { // check recv queue - size_t len = recv_queue[0].len; // take from top of queue - memcpy(dest, recv_queue[0].buf, len); - - BLE_DEBUG_PRINTLN("readBytes: sz=%d, hdr=%d", len, (uint32_t) dest[0]); - - recv_queue_len--; - if (recv_queue_len > 0) { - memmove(&recv_queue[0], &recv_queue[1], recv_queue_len * sizeof(Frame)); - } - return len; + Frame frame; + if (xQueueReceive(recv_queue, &frame, 0) == pdTRUE) { // check recv queue + memcpy(dest, frame.buf, frame.len); + BLE_DEBUG_PRINTLN("readBytes: sz=%d, hdr=%d", (uint32_t) frame.len, (uint32_t) dest[0]); + return frame.len; } if (pServer->getConnectedCount() == 0) { diff --git a/src/helpers/esp32/SerialBLEInterface.h b/src/helpers/esp32/SerialBLEInterface.h index 573983b2..fba94ed4 100644 --- a/src/helpers/esp32/SerialBLEInterface.h +++ b/src/helpers/esp32/SerialBLEInterface.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include class SerialBLEInterface : public BaseSerialInterface, BLESecurityCallbacks, BLEServerCallbacks, BLECharacteristicCallbacks { BLEServer *pServer; @@ -36,13 +38,14 @@ class SerialBLEInterface : public BaseSerialInterface, BLESecurityCallbacks, BLE }; #define FRAME_QUEUE_SIZE 16 - int recv_queue_len; - Frame recv_queue[FRAME_QUEUE_SIZE]; + StaticQueue_t recv_queue_state; + uint8_t recv_queue_storage[FRAME_QUEUE_SIZE * sizeof(Frame)]; + QueueHandle_t recv_queue; // filled by the BLE stack task (onWrite), drained by loop() int send_queue_len; Frame send_queue[FRAME_QUEUE_SIZE]; void clearBuffers() { - recv_queue_len = 0; send_queue_len = 0; + xQueueReset(recv_queue); send_queue_len = 0; #ifdef MECK_BLE_SMALL_MTU_SPLIT _tx_off = 0; _rx_len = -1; #endif @@ -83,7 +86,10 @@ public: _last_write = 0; last_conn_id = 0; memset(_remote_bda, 0, 6); - send_queue_len = recv_queue_len = 0; + recv_queue = xQueueCreateStatic( + FRAME_QUEUE_SIZE, sizeof(Frame), recv_queue_storage, &recv_queue_state + ); + send_queue_len = 0; } /** diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index c5484bba..1547d707 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -698,11 +698,11 @@ void EnvironmentSensorManager::stop_gps() { } void EnvironmentSensorManager::loop() { - static long next_gps_update = 0; + static unsigned long next_gps_update = 0; #if ENV_INCLUDE_GPS _location->loop(); - if (millis() > next_gps_update) { + if ((long)(millis() - next_gps_update) > 0) { if(gps_active){ #ifdef RAK_WISBLOCK_GPS diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index 574570a3..62e2e684 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -41,7 +41,7 @@ class MicroNMEALocationProvider : public LocationProvider { RefCountedDigitalPin* _peripher_power; int _pin_reset; int _pin_en; - long next_check = 0; + unsigned long next_check = 0; long time_valid = 0; public : @@ -124,7 +124,7 @@ public : if (!isValid()) time_valid = 0; - if (millis() > next_check) { + if ((long)(millis() - next_check) > 0) { next_check = millis() + 1000; if (_time_sync_needed && time_valid > 2) { if (_clock != NULL) {