diff --git a/repeater/packet_router.py b/repeater/packet_router.py index 0b65d16..9f2f457 100644 --- a/repeater/packet_router.py +++ b/repeater/packet_router.py @@ -475,10 +475,17 @@ class PacketRouter: # as routing hashes and log bogus duplicate rows. elif payload_type == ControlHandler.payload_type(): + # MeshCore never relays control packets: the direct high-bit discovery + # subset is explicitly released (Mesh.cpp), and any other control + # payload hits the switch default that does not flood-route unknown + # types. Mark do-not-retransmit unconditionally so a repeater with + # discovery disabled still does not forward control/discovery traffic + # to the engine. Discovery responses are injected as their own TX, so + # this does not suppress them. + packet.mark_do_not_retransmit() # Process control/discovery packet if self.daemon.discovery_helper: await self.daemon.discovery_helper.control_handler(packet) - packet.mark_do_not_retransmit() # Deliver to companions via daemon (frame servers push PUSH_CODE_CONTROL_DATA 0x8E) deliver = getattr(self.daemon, "deliver_control_data", None) if deliver: diff --git a/tests/test_packet_router.py b/tests/test_packet_router.py index 4087b38..d0218b3 100644 --- a/tests/test_packet_router.py +++ b/tests/test_packet_router.py @@ -546,6 +546,19 @@ class TestPacketRouterRoutingBranches(unittest.IsolatedAsyncioTestCase): daemon.deliver_control_data.assert_awaited_once() daemon.repeater_handler.assert_awaited_once() + async def test_route_control_marks_do_not_retransmit_when_discovery_disabled(self): + """With discovery disabled (discovery_helper is None), control packets must + still be marked do-not-retransmit so the engine does not relay them. MeshCore + never forwards control packets regardless of whether discovery is enabled.""" + daemon = _make_daemon() + daemon.discovery_helper = None + daemon.deliver_control_data = AsyncMock() + router = PacketRouter(daemon) + pkt = _make_packet(ControlHandler.payload_type()) + pkt.path_len = 0 + await router._route_packet(pkt) + pkt.mark_do_not_retransmit.assert_called_once() + async def test_route_advert_delivers_to_helpers_and_engine(self): daemon = _make_daemon() daemon.advert_helper = MagicMock()