From affb99ad374e5fbd3a38c6d8e386caaea876f3ba Mon Sep 17 00:00:00 2001 From: nope Date: Sat, 7 Mar 2026 14:13:30 -0800 Subject: [PATCH] isLooped checks for any duplicate prefixes previous implemenation only checked for duplicates self_id. A node would happily forward a packet that had signs it was already looped. Since not all nodes in a network will enable loop detection I want configured nodes to drop these packets. This is a quadratic loop, but it's upper bound is 64. It can be improved with a better data structure but I wanted to keep it simple. The package doesn't have a test framework so I wrote a small harness to double check the behavior. All the 'self' tests pass with the previous impl. ``` runTest(1, {0x11, 0x22, 0x33}, max_loop_strict, false, "no dups"); runTest(1, {0xAA, 0x22}, max_loop_strict, true, "dup with self"); runTest(1, {0x11, 0x11, 0x22, 0x33}, max_loop_strict, true, "dup in path"); runTest(2, {0xAA, 0x22, 0xBB, 0x44}, max_loop_strict, false, "2-byte no dup"); runTest(2, {0xAA, 0xBB, 0xCC, 0xDD}, max_loop_strict, true, "2-byte dup with self"); runTest(2, {0x00, 0x11, 0x00, 0x11}, max_loop_strict, true, "2-byte dup in path"); runTest(3, {0xAA, 0xBB, 0xCC}, max_loop_strict, true, "3-byte dup with self"); runTest(3, {0x11, 0x22, 0x33, 0x11, 0x22, 0x33}, max_loop_strict, true, "3-byte dup in path"); runTest(1, {0x11, 0x11, 0x11, 0x11}, max_loop_minimal, false, "4 repeats: under minimal limit"); runTest(1, {0x11, 0x11, 0x11, 0x11, 0x11}, max_loop_minimal, true, "5 repeats: over minimal limit"); runTest(1, {0xAA, 0xAA, 0xAA}, max_loop_minimal, false, "3 repeats and self: under minimal limit"); runTest(1, {0xAA, 0xAA, 0xAA, 0xAA}, max_loop_minimal, true, "4 repeats and self: over minimal limit"); ``` --- examples/simple_repeater/MyMesh.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 5ac99db09..bd04cfa03 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -402,15 +402,21 @@ static uint8_t max_loop_strict[] = { 0, /* 1-byte */ 1, /* 2-byte */ 1, /* 3 bool MyMesh::isLooped(const mesh::Packet* packet, const uint8_t max_counters[]) { uint8_t hash_size = packet->getPathHashSize(); - uint8_t hash_count = packet->getPathHashCount(); - uint8_t n = 0; + uint8_t path_byte_len = packet->getPathByteLen(); + uint8_t limit = max_counters[hash_size]; const uint8_t* path = packet->path; - while (hash_count > 0) { // count how many times this node is already in the path - if (self_id.isHashMatch(path, hash_size)) n++; - hash_count--; - path += hash_size; + + for (uint8_t i = 0; i < path_byte_len; i += hash_size) { + uint8_t n = 0; + + if (self_id.isHashMatch(&path[i], hash_size)) n++; + + for (uint8_t j = i + hash_size; j < path_byte_len; j += hash_size) { + if (memcmp(&path[i], &path[j], hash_size) == 0) n++; + } + if (n >= limit) return true; } - return n >= max_counters[hash_size]; + return false; } bool MyMesh::allowPacketForward(const mesh::Packet *packet) {