From ec3b47bbc290b2db78e9846b0fa3b6f28ed2a2da Mon Sep 17 00:00:00 2001 From: Kaj Schittecat Date: Sat, 13 Jun 2026 22:11:17 +0200 Subject: [PATCH] fix: restore 'repeats heard' on scoped floods + guard trace-route crash - MyMesh.cpp logRxRaw: the self-echo parser tested (raw[0] & 0x80) for transport codes, but 0x80 is the top of the payload VERSION field, not a flag. Transport codes are present iff route_type (raw[0]&0x03) is TRANSPORT_FLOOD/DIRECT. Since beta_12's region scope, scoped floods carry transport codes -> the parser hashed the wrong payload slice -> the echo never matched -> 'repeats heard' showed 0 for anyone with a region set. Now route-type aware (matches uiStashRxMeta). Also fixed the diagnostic dst= decoder + the header-layout comment. - MyMesh.h uiSendTraceRoute: walking c.out_path with an unchecked out_path_len (uint8_t, can be 65..254 if a contact's path is corrupt) overran sendDirect's payload memcpy -> reboot when tapping 'Trace route' on a sent DM. Clamp to <= MAX_PATH_SIZE, else fall back to the single-hop trace. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/MyMesh.cpp | 13 +++++++++---- src/MyMesh.h | 5 +++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/MyMesh.cpp b/src/MyMesh.cpp index 925de32..b73fa3e 100644 --- a/src/MyMesh.cpp +++ b/src/MyMesh.cpp @@ -1359,8 +1359,10 @@ void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { #if defined(DISPLAY_CLASS) // Diagnostic: log EVERY received frame so we can prove what reaches the // radio. Header byte layout is - // [hasXportCodes:1][reserved:1][payload_type:4][route_type:2] - // so payload_type = (raw[0]>>2)&0x0F and route_type = raw[0]&0x03. + // [version:2][payload_type:4][route_type:2] (bits 7..0) + // so payload_type = (raw[0]>>2)&0x0F and route_type = raw[0]&0x03. The 4 + // transport-code bytes follow the header iff route_type is a TRANSPORT_* one + // (there is NO "hasXportCodes" bit at 0x80 — that's the top of the version field). if (_ui && len > 0) { const uint8_t ptype = (raw[0] >> 2) & 0x0F; const uint8_t route = raw[0] & 0x03; @@ -1390,7 +1392,8 @@ void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { // Header is byte 0; transport codes (if present) are 1-4; path_len is // next; then path bytes; then payload. We just want the first byte of // the payload as dest_hash for TXT/RSP/ACK style packets. - const bool has_xport = (raw[0] & 0x80) != 0; + const uint8_t rt0 = raw[0] & 0x03; + const bool has_xport = (rt0 == ROUTE_TYPE_TRANSPORT_FLOOD || rt0 == ROUTE_TYPE_TRANSPORT_DIRECT); int payload_start = 1 + (has_xport ? 4 : 0); if (payload_start < len) { uint8_t path_byte = raw[payload_start]; @@ -1421,7 +1424,9 @@ void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { // and bump the matching sent message's count. The fp ring only holds our own // recent sends, so other nodes' traffic can't false-match. if (len > 0 && isMsgFloodType((raw[0] >> 2) & 0x0F)) { - const bool has_xp = (raw[0] & 0x80) != 0; + const uint8_t rt = raw[0] & 0x03; // route_type (PH_ROUTE_MASK) + const bool has_xp = (rt == ROUTE_TYPE_TRANSPORT_FLOOD || // 4 transport-code bytes follow the + rt == ROUTE_TYPE_TRANSPORT_DIRECT); // header iff route is a TRANSPORT_* one const int ps = 1 + (has_xp ? 4 : 0); if (ps < len) { const uint8_t pb = raw[ps]; diff --git a/src/MyMesh.h b/src/MyMesh.h index 67ce04a..7bfa059 100644 --- a/src/MyMesh.h +++ b/src/MyMesh.h @@ -480,8 +480,9 @@ public: _ui_trace_ping_tag = tag; mesh::Packet* pkt = createTrace(tag, 0, flags); if (!pkt) { _ui_trace_ping_tag = 0; return 0; } - if (c.out_path_len != OUT_PATH_UNKNOWN && c.out_path_len > 0) { - sendDirect(pkt, c.out_path, c.out_path_len); // walk the full route + if (c.out_path_len != OUT_PATH_UNKNOWN && c.out_path_len > 0 && + c.out_path_len <= MAX_PATH_SIZE) { // clamp: a corrupt out_path_len (>64) + sendDirect(pkt, c.out_path, c.out_path_len); // would overrun sendDirect's payload memcpy -> reboot } else { uint8_t hash_sz = (uint8_t)(_prefs.path_hash_mode + 1); if (hash_sz == 0 || hash_sz > 4) hash_sz = 1;