diff --git a/src/mesh/Default.h b/src/mesh/Default.h index b6d93eb21..13e72f781 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -49,7 +49,6 @@ enum class TrafficType { POSITION, TELEMETRY }; #define default_traffic_mgmt_tracker_position_min_interval_secs (60 * 60) // 1 hour // Role cap: lost-and-found origins may refresh a duplicate position this often, so a lost // device updates frequently without flooding. (Quantised to the dedup tick: ~2 ticks.) -// Unlike before, lost-and-found is NOT exempt from the relayed precision clamp. #define default_traffic_mgmt_lost_and_found_position_min_interval_secs (15 * 60) // 15 minutes // Hop scaling defaults diff --git a/src/modules/TrafficManagementModule.cpp b/src/modules/TrafficManagementModule.cpp index f0892e459..7a7256c32 100644 --- a/src/modules/TrafficManagementModule.cpp +++ b/src/modules/TrafficManagementModule.cpp @@ -1069,14 +1069,14 @@ uint8_t TrafficManagementModule::computePositionFingerprint(int32_t lat_truncate /// Runs BEFORE RoutingModule in callModules(): STOP fully consumes the packet (no rebroadcast), /// ignoreRequest suppresses the default NAK for want_response packets, and exhaustRequested -/// (set by alterReceived) makes perhapsRebroadcast() force hop_limit=0 on the relayed copy. +/// makes perhapsRebroadcast() force hop_limit=0 on the relayed copy. ProcessMessage TrafficManagementModule::handleReceived(const meshtastic_MeshPacket &mp) { if (!moduleConfig.has_traffic_management) return ProcessMessage::CONTINUE; ignoreRequest = false; - exhaustRequested = false; // Reset per-packet; may be set by alterReceived() below + exhaustRequested = false; // Reset per-packet exhaustRequestedFrom = 0; exhaustRequestedId = 0; incrementStat(&stats.packets_inspected); @@ -1182,52 +1182,6 @@ ProcessMessage TrafficManagementModule::handleReceived(const meshtastic_MeshPack return ProcessMessage::CONTINUE; } -void TrafficManagementModule::alterReceived(meshtastic_MeshPacket &mp) -{ - if (!moduleConfig.has_traffic_management) - return; - - if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag) - return; - - if (isFromUs(&mp)) - return; - - // exhaust_hop_telemetry / exhaust_hop_position / router_preserve_hops: shelved until the - // right heuristics are clearer; exhaustRequested stays false and rebroadcast is normal. - - const bool isPosition = mp.decoded.portnum == meshtastic_PortNum_POSITION_APP; - - // ------------------------------------------------------------------------- - // Relayed Position Precision Clamp - // ------------------------------------------------------------------------- - // Never forward more-precise coordinates than the channel is configured to carry - // (chanPrec==0 = sharing disabled on channel: skip). Ham mode is exempt; lost-and-found - // is not. Compile USERPREFS_TMM_APPLY_TO_PRIVATE_CHANNELS to extend to private channels. - if (!owner.is_licensed && isPosition && isBroadcast(mp.to)) { -#ifdef USERPREFS_TMM_APPLY_TO_PRIVATE_CHANNELS - const bool shouldClamp = true; -#else - const bool shouldClamp = channels.isWellKnownChannel(mp.channel); -#endif - if (shouldClamp) { - const uint32_t chanPrec = getPositionPrecisionForChannel(mp.channel); - if (chanPrec > 0) { - meshtastic_Position pos = meshtastic_Position_init_default; - if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Position_msg, &pos)) { - const uint32_t packetPrec = pos.precision_bits > 0 ? pos.precision_bits : 32u; - if (packetPrec > chanPrec) { - applyPositionPrecision(pos, chanPrec); - mp.decoded.payload.size = pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), - &meshtastic_Position_msg, &pos); - logAction("clamp", &mp, "precision"); - } - } - } - } - } -} - // ============================================================================= // Periodic Maintenance // ============================================================================= diff --git a/src/modules/TrafficManagementModule.h b/src/modules/TrafficManagementModule.h index 631673d75..44d240080 100644 --- a/src/modules/TrafficManagementModule.h +++ b/src/modules/TrafficManagementModule.h @@ -95,7 +95,7 @@ class TrafficManagementModule : public MeshModule, private concurrency::OSThread void purgeAll(); /// True when perhapsRebroadcast() must force hop_limit=0 for this packet, regardless of - /// router_preserve_hops or favorite-node logic (set by alterReceived()). + /// router_preserve_hops or favorite-node logic. bool shouldExhaustHops(const meshtastic_MeshPacket &mp) const { return exhaustRequested && exhaustRequestedFrom == getFrom(&mp) && exhaustRequestedId == mp.id; @@ -116,8 +116,6 @@ class TrafficManagementModule : public MeshModule, private concurrency::OSThread ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override; /// Promiscuous: this module inspects every packet. bool wantPacket(const meshtastic_MeshPacket *p) override { return true; } - /// Mutate relayed packets in place (position precision clamp). - void alterReceived(meshtastic_MeshPacket &mp) override; /// 60 s maintenance sweep: expire timed state, saturate tick stamps, reconcile with NodeDB. int32_t runOnce() override; /// Clear all per-node traffic state (protected for test shims). @@ -299,8 +297,8 @@ class TrafficManagementModule : public MeshModule, private concurrency::OSThread meshtastic_TrafficManagementStats stats; - // Set during alterReceived() when the packet's hops should be exhausted; checked by - // perhapsRebroadcast() for the matching packet key. Reset at start of handleReceived(). + // Set when the packet's hops should be exhausted; checked by perhapsRebroadcast() for the + // matching packet key. Reset at start of handleReceived(). bool exhaustRequested = false; NodeNum exhaustRequestedFrom = 0; PacketId exhaustRequestedId = 0; diff --git a/test/test_traffic_management/test_main.cpp b/test/test_traffic_management/test_main.cpp index 94d35c4e4..e44c62547 100644 --- a/test/test_traffic_management/test_main.cpp +++ b/test/test_traffic_management/test_main.cpp @@ -292,12 +292,6 @@ static meshtastic_MeshPacket makePositionPacketWithPrecision(NodeNum from, int32 return packet; } -static bool decodePositionPayload(const meshtastic_MeshPacket &packet, meshtastic_Position &out) -{ - out = meshtastic_Position_init_zero; - return pb_decode_from_bytes(packet.decoded.payload.bytes, packet.decoded.payload.size, &meshtastic_Position_msg, &out); -} - // Primary channel with a well-known single-byte PSK and the (empty -> preset) // default name, so Channels::isWellKnownChannel(0) is true. static void installWellKnownPrimaryChannel() @@ -2322,8 +2316,6 @@ static void test_tm_alterReceived_telemetryBroadcast_hopLimitUnchanged(void) /** * Verify alterReceived does not modify unicast or local-origin packets. - * The precision clamp (the only active alterReceived path) only fires for - * broadcast position packets from remote nodes - these should be untouched. */ static void test_tm_alterReceived_skipsLocalAndUnicast(void) { @@ -3163,36 +3155,27 @@ static void test_tm_unknownRole_noUserBit_appliesFullInterval(void) } /** - * Verify a LOST_AND_FOUND origin now GETS the relayed precision clamp - the - * anti-dox exemption was removed, so a relayed position more precise than the - * channel setting is clamped down to the channel ceiling like any other node's. + * Verify a relayed position broadcast more precise than the channel setting passes through + * handleReceived/alterReceived unmodified. Relays must forward position payloads byte-for-byte + * so the sender's XEdDSA signature still verifies downstream. */ -static void test_tm_lostAndFoundRole_getsAlterReceivedPrecisionClamp(void) +static void test_tm_relayedPosition_payloadUnmodified(void) { - // Set channel precision ceiling to 13 bits. Must be <= MAX_POSITION_PRECISION_PUBLIC_KEY - // (15) - well-known channels have a public PSK (size==1), so getPositionPrecisionForChannel - // clamps any value above 15 via usesPublicKey(). installWellKnownPrimaryChannelWithPrecision(13); - mockNodeDB->setCachedNode(kRemoteNode); - mockNodeDB->setCachedNodeRole(meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND); TrafficManagementModuleTestShim module; - // Full-precision packet - 32 bits - exceeds the channel cap. - const uint32_t fullPrecision = 32; - meshtastic_MeshPacket packet = makePositionPacketWithPrecision(kRemoteNode, 374221234, -1220845678, fullPrecision); + meshtastic_MeshPacket packet = makePositionPacketWithPrecision(kRemoteNode, 374221234, -1220845678, 32); packet.hop_start = 3; - packet.hop_limit = 2; // relayed (hop_limit < hop_start) so clamp logic applies + packet.hop_limit = 2; + const meshtastic_Data_payload_t original = packet.decoded.payload; + TEST_ASSERT_EQUAL_INT(static_cast(ProcessMessage::CONTINUE), static_cast(module.handleReceived(packet))); module.alterReceived(packet); - meshtastic_Position out; - TEST_ASSERT_TRUE(decodePositionPayload(packet, out)); - // Clamped to channel ceiling (13 bits) - lost-and-found is no longer exempt. - // Note: precision must be <= MAX_POSITION_PRECISION_PUBLIC_KEY (15); well-known - // channels always have a public PSK so getPositionPrecisionForChannel caps at 15. - TEST_ASSERT_EQUAL_UINT32(13, out.precision_bits); + TEST_ASSERT_EQUAL_UINT32(original.size, packet.decoded.payload.size); + TEST_ASSERT_EQUAL_MEMORY(original.bytes, packet.decoded.payload.bytes, original.size); } // --------------------------------------------------------------------------- @@ -3405,7 +3388,7 @@ TM_TEST_ENTRY void setup() RUN_TEST(test_tm_specialRole_evictedLastUnderPressure); RUN_TEST(test_tm_trackerRole_doesNotLengthenShorterOperatorInterval); RUN_TEST(test_tm_lostAndFoundRole_capsDedupAtFifteenMinutes); - RUN_TEST(test_tm_lostAndFoundRole_getsAlterReceivedPrecisionClamp); + RUN_TEST(test_tm_relayedPosition_payloadUnmodified); RUN_TEST(test_tm_unknownRole_noDbEntry_appliesFullInterval); RUN_TEST(test_tm_unknownRole_noUserBit_appliesFullInterval); RUN_TEST(test_tm_fuzz_nodenum_blitz); diff --git a/userPrefs.jsonc b/userPrefs.jsonc index f50bbaf0f..c9af7b963 100644 --- a/userPrefs.jsonc +++ b/userPrefs.jsonc @@ -47,7 +47,6 @@ // "USERPREFS_EVENT_MODE": "1", // "USERPREFS_EVENT_MODE_HOP_LIMIT": "3", // Event-mode default and firmware-generated/relay hop cap (0-7; default 3) // "USERPREFS_BLOCK_POSITION_ON_EVENT_CHANNEL": "1", // Block location TX + discard inbound location on channels keyed with USERPREFS_CHANNEL_0_PSK. Defaults off, and must be set explicitly. - // "USERPREFS_TMM_APPLY_TO_PRIVATE_CHANNELS": "1", // Extend TMM position dedup and precision clamping to private/custom-key channels (default: well-known channels only) // "USERPREFS_FIRMWARE_EDITION": "meshtastic_FirmwareEdition_BURNING_MAN", // "USERPREFS_FIXED_BLUETOOTH": "121212", // "USERPREFS_FIXED_GPS": "",