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

This commit is contained in:
pelgraine committed 2026-10-08 20:28:58 +11:00
1 parent 46f46035ba
commit 7ea461e443
9 files changed
+104 -38

No files matched your search

+3 -2
View File
@@ -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;
+7 -1
View File
@@ -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];
+7 -5
View File
@@ -1,4 +1,5 @@
#include <helpers/AdvertDataHelpers.h>
#include <helpers/UTF8Helpers.h>
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;
+1 -1
View File
@@ -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
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
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<uint8_t>(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<uint8_t>(text[offset + i]))) {
complete = false;
break;
}
}
if (!complete) break;
if (sequence_length == 3) {
const uint8_t second = static_cast<uint8_t>(text[offset + 1]);
if ((first == 0xE0 && second < 0xA0) || (first == 0xED && second > 0x9F)) break;
} else if (sequence_length == 4) {
const uint8_t second = static_cast<uint8_t>(text[offset + 1]);
if ((first == 0xF0 && second < 0x90) || (first == 0xF4 && second > 0x8F)) break;
}
offset += sequence_length;
}
return offset;
}
} // namespace mesh
+16 -21
View File
@@ -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) {
+10 -4
View File
@@ -5,6 +5,8 @@
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
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;
}
/**
@@ -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
@@ -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) {