From e8785dd9b0fd4ceace644f19d68d42ff8c8a8cbc Mon Sep 17 00:00:00 2001 From: realtag Date: Mon, 16 Feb 2026 22:35:20 +0000 Subject: [PATCH 1/4] discover sends a single repeater discovery request and populates the neighbor list; self is excluded --- examples/simple_repeater/MyMesh.cpp | 40 +++++++++++++++++++++++++++++ examples/simple_repeater/MyMesh.h | 1 + 2 files changed, 41 insertions(+) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 65e0cee5..e84ce08e 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -738,6 +738,37 @@ void MyMesh::onControlDataRecv(mesh::Packet* packet) { sendZeroHop(resp, getRetransmitDelay(resp)*4); // apply random delay (widened x4), as multiple nodes can respond to this } } + } else if (type == CTL_TYPE_NODE_DISCOVER_RESP && packet->payload_len >= 6) { + uint8_t node_type = packet->payload[0] & 0x0F; + if (node_type != ADV_TYPE_REPEATER) { + return; + } + if (packet->payload_len < 6 + PUB_KEY_SIZE) { + MESH_DEBUG_PRINTLN("onControlDataRecv: DISCOVER_RESP pubkey too short: %d", (uint32_t)packet->payload_len); + return; + } + + mesh::Identity id(&packet->payload[6]); + if (id.matches(self_id)) { + return; + } + putNeighbour(id, rtc_clock.getCurrentTime(), packet->getSNR()); + } +} + +void MyMesh::sendNodeDiscoverReq() { + if (_prefs.disable_fwd) return; + + uint8_t data[10]; + data[0] = CTL_TYPE_NODE_DISCOVER_REQ; // prefix_only=0 + data[1] = (1 << ADV_TYPE_REPEATER); + getRNG()->random(&data[2], 4); // tag + uint32_t since = 0; + memcpy(&data[6], &since, 4); + + auto pkt = createControlData(data, sizeof(data)); + if (pkt) { + sendZeroHop(pkt); } } @@ -1168,6 +1199,15 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply } else { strcpy(reply, "Err - ??"); } + } else if (memcmp(command, "discover", 8) == 0) { + const char* sub = command + 8; + while (*sub == ' ') sub++; + if (*sub != 0) { + strcpy(reply, "Err - discover has no options"); + } else { + sendNodeDiscoverReq(); + strcpy(reply, "OK - Discover sent"); + } } else{ _cli.handleCommand(sender_timestamp, command, reply); // common CLI commands } diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index 8388e29c..6cded9cf 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -116,6 +116,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { #endif void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr); + void sendNodeDiscoverReq(); uint8_t handleLoginReq(const mesh::Identity& sender, const uint8_t* secret, uint32_t sender_timestamp, const uint8_t* data, bool is_flood); uint8_t handleAnonRegionsReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data); uint8_t handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender_timestamp, const uint8_t* data); From 87c78a98bdef070b60f694eb8c4f43fb6bd57d83 Mon Sep 17 00:00:00 2001 From: realtag Date: Tue, 17 Feb 2026 01:04:14 +0000 Subject: [PATCH 2/4] discover.neighbors sends a tagged repeater discovery request and only accepts matching repeater responses --- examples/simple_repeater/MyMesh.cpp | 21 ++++++++++++++++++--- examples/simple_repeater/MyMesh.h | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index e84ce08e..aec4ff3e 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -748,6 +748,16 @@ void MyMesh::onControlDataRecv(mesh::Packet* packet) { return; } + if (pending_discover_tag == 0 || millisHasNowPassed(pending_discover_until)) { + pending_discover_tag = 0; + return; + } + uint32_t tag; + memcpy(&tag, &packet->payload[2], 4); + if (tag != pending_discover_tag) { + return; + } + mesh::Identity id(&packet->payload[6]); if (id.matches(self_id)) { return; @@ -763,6 +773,8 @@ void MyMesh::sendNodeDiscoverReq() { data[0] = CTL_TYPE_NODE_DISCOVER_REQ; // prefix_only=0 data[1] = (1 << ADV_TYPE_REPEATER); getRNG()->random(&data[2], 4); // tag + memcpy(&pending_discover_tag, &data[2], 4); + pending_discover_until = futureMillis(30000); uint32_t since = 0; memcpy(&data[6], &since, 4); @@ -832,6 +844,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc _prefs.advert_loc_policy = ADVERT_LOC_PREFS; _prefs.adc_multiplier = 0.0f; // 0.0f means use default board multiplier + + pending_discover_tag = 0; + pending_discover_until = 0; } void MyMesh::begin(FILESYSTEM *fs) { @@ -1199,11 +1214,11 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply } else { strcpy(reply, "Err - ??"); } - } else if (memcmp(command, "discover", 8) == 0) { - const char* sub = command + 8; + } else if (memcmp(command, "discover.neighbors", 18) == 0) { + const char* sub = command + 18; while (*sub == ' ') sub++; if (*sub != 0) { - strcpy(reply, "Err - discover has no options"); + strcpy(reply, "Err - discover.neighbors has no options"); } else { sendNodeDiscoverReq(); strcpy(reply, "OK - Discover sent"); diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index 6cded9cf..f0e7cc10 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -97,6 +97,8 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { RegionEntry* load_stack[8]; RegionEntry* recv_pkt_region; RateLimiter discover_limiter, anon_limiter; + uint32_t pending_discover_tag; + unsigned long pending_discover_until; bool region_load_active; unsigned long dirty_contacts_expiry; #if MAX_NEIGHBOURS From bf9c6cb50f91de89dfbc7dffc24653f68816eda7 Mon Sep 17 00:00:00 2001 From: realtag Date: Tue, 17 Feb 2026 01:22:17 +0000 Subject: [PATCH 3/4] Increased the timeout timer to 60 seconds, up from 30 seconds. --- examples/simple_repeater/MyMesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index aec4ff3e..e2bf0330 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -774,7 +774,7 @@ void MyMesh::sendNodeDiscoverReq() { data[1] = (1 << ADV_TYPE_REPEATER); getRNG()->random(&data[2], 4); // tag memcpy(&pending_discover_tag, &data[2], 4); - pending_discover_until = futureMillis(30000); + pending_discover_until = futureMillis(60000); uint32_t since = 0; memcpy(&data[6], &since, 4); From 0770618ee2329efaead80bfb78986ee459fd2db4 Mon Sep 17 00:00:00 2001 From: realtag Date: Tue, 17 Feb 2026 01:39:04 +0000 Subject: [PATCH 4/4] Allow repeater discovery even if repeater mode is disabled on the requesting repeater. --- examples/simple_repeater/MyMesh.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index e2bf0330..20be1010 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -767,8 +767,6 @@ void MyMesh::onControlDataRecv(mesh::Packet* packet) { } void MyMesh::sendNodeDiscoverReq() { - if (_prefs.disable_fwd) return; - uint8_t data[10]; data[0] = CTL_TYPE_NODE_DISCOVER_REQ; // prefix_only=0 data[1] = (1 << ADV_TYPE_REPEATER);