mirror of
https://github.com/meshtastic/firmware.git
synced 2026-03-30 04:54:14 -04:00
Align telemetry broadcast want_response behavior with traceroute (#9717)
* Align telemetry broadcast want_response behavior with traceroute * Fixes * Reduce side-effects by making the telemetry modules handle the ignorerequest * Remove unnecessary ignoreRequest flag * Try inheriting from MeshModule * Add exclusion for sensor/router roles and add base telem module
This commit is contained in:
@@ -106,6 +106,18 @@ class MeshModule
|
||||
/* We allow modules to ignore a request without sending an error if they have a specific reason for it. */
|
||||
bool ignoreRequest = false;
|
||||
|
||||
/**
|
||||
* Check if the current request is a multi-hop broadcast. Modules should call this in allocReply()
|
||||
* and return NULL to prevent reply storms from broadcast requests that have already been relayed.
|
||||
*/
|
||||
bool isMultiHopBroadcastRequest()
|
||||
{
|
||||
if (currentRequest && isBroadcast(currentRequest->to) && currentRequest->hop_limit < currentRequest->hop_start) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** If a bound channel name is set, we will only accept received packets that come in on that channel.
|
||||
* A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface
|
||||
* are allowed on any channel (this lets the local user do anything).
|
||||
|
||||
@@ -321,6 +321,10 @@ bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m)
|
||||
meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||
ignoreRequest = true;
|
||||
return NULL;
|
||||
}
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseTelemetryModule.h"
|
||||
|
||||
#ifndef AIR_QUALITY_TELEMETRY_MODULE_ENABLE
|
||||
#define AIR_QUALITY_TELEMETRY_MODULE_ENABLE 0
|
||||
#endif
|
||||
@@ -17,6 +19,7 @@
|
||||
|
||||
class AirQualityTelemetryModule : private concurrency::OSThread,
|
||||
public ScanI2CConsumer,
|
||||
public BaseTelemetryModule,
|
||||
public ProtobufModule<meshtastic_Telemetry>
|
||||
{
|
||||
CallbackObserver<AirQualityTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||
|
||||
14
src/modules/Telemetry/BaseTelemetryModule.h
Normal file
14
src/modules/Telemetry/BaseTelemetryModule.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "NodeDB.h"
|
||||
#include "configuration.h"
|
||||
|
||||
class BaseTelemetryModule
|
||||
{
|
||||
protected:
|
||||
bool isSensorOrRouterRole() const
|
||||
{
|
||||
return config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER;
|
||||
}
|
||||
};
|
||||
@@ -19,8 +19,7 @@
|
||||
int32_t DeviceTelemetryModule::runOnce()
|
||||
{
|
||||
refreshUptime();
|
||||
bool isImpoliteRole =
|
||||
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_ROUTER);
|
||||
bool isImpoliteRole = isSensorOrRouterRole();
|
||||
if (((lastSentToMesh == 0) ||
|
||||
((uptimeLastMs - lastSentToMesh) >=
|
||||
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
||||
@@ -60,6 +59,10 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
||||
meshtastic_MeshPacket *DeviceTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||
ignoreRequest = true;
|
||||
return NULL;
|
||||
}
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#pragma once
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BaseTelemetryModule.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
|
||||
class DeviceTelemetryModule : private concurrency::OSThread,
|
||||
public BaseTelemetryModule,
|
||||
public ProtobufModule<meshtastic_Telemetry>
|
||||
{
|
||||
CallbackObserver<DeviceTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||
CallbackObserver<DeviceTelemetryModule, const meshtastic::Status *>(this, &DeviceTelemetryModule::handleStatusUpdate);
|
||||
|
||||
@@ -577,6 +577,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||
ignoreRequest = true;
|
||||
return NULL;
|
||||
}
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseTelemetryModule.h"
|
||||
|
||||
#ifndef ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE
|
||||
#define ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE 0
|
||||
#endif
|
||||
@@ -17,6 +19,7 @@
|
||||
|
||||
class EnvironmentTelemetryModule : private concurrency::OSThread,
|
||||
public ScanI2CConsumer,
|
||||
public BaseTelemetryModule,
|
||||
public ProtobufModule<meshtastic_Telemetry>
|
||||
{
|
||||
CallbackObserver<EnvironmentTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||
|
||||
@@ -192,6 +192,10 @@ bool HealthTelemetryModule::getHealthTelemetry(meshtastic_Telemetry *m)
|
||||
meshtastic_MeshPacket *HealthTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||
ignoreRequest = true;
|
||||
return NULL;
|
||||
}
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
|
||||
@@ -4,12 +4,15 @@
|
||||
|
||||
#pragma once
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BaseTelemetryModule.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
class HealthTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
|
||||
class HealthTelemetryModule : private concurrency::OSThread,
|
||||
public BaseTelemetryModule,
|
||||
public ProtobufModule<meshtastic_Telemetry>
|
||||
{
|
||||
CallbackObserver<HealthTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||
CallbackObserver<HealthTelemetryModule, const meshtastic::Status *>(this, &HealthTelemetryModule::handleStatusUpdate);
|
||||
|
||||
@@ -217,6 +217,10 @@ bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m)
|
||||
meshtastic_MeshPacket *PowerTelemetryModule::allocReply()
|
||||
{
|
||||
if (currentRequest) {
|
||||
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||
ignoreRequest = true;
|
||||
return NULL;
|
||||
}
|
||||
auto req = *currentRequest;
|
||||
const auto &p = req.decoded;
|
||||
meshtastic_Telemetry scratch;
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BaseTelemetryModule.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
|
||||
class PowerTelemetryModule : private concurrency::OSThread,
|
||||
public BaseTelemetryModule,
|
||||
public ProtobufModule<meshtastic_Telemetry>
|
||||
{
|
||||
CallbackObserver<PowerTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||
CallbackObserver<PowerTelemetryModule, const meshtastic::Status *>(this, &PowerTelemetryModule::handleStatusUpdate);
|
||||
|
||||
116
test/test_mesh_module/test_main.cpp
Normal file
116
test/test_mesh_module/test_main.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "MeshModule.h"
|
||||
#include "MeshTypes.h"
|
||||
#include "TestUtil.h"
|
||||
#include <unity.h>
|
||||
|
||||
// Minimal concrete subclass for testing the base class helper
|
||||
class TestModule : public MeshModule
|
||||
{
|
||||
public:
|
||||
TestModule() : MeshModule("TestModule") {}
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; }
|
||||
using MeshModule::currentRequest;
|
||||
using MeshModule::isMultiHopBroadcastRequest;
|
||||
};
|
||||
|
||||
static TestModule *testModule;
|
||||
static meshtastic_MeshPacket testPacket;
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
testModule = new TestModule();
|
||||
memset(&testPacket, 0, sizeof(testPacket));
|
||||
TestModule::currentRequest = &testPacket;
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
TestModule::currentRequest = NULL;
|
||||
delete testModule;
|
||||
}
|
||||
|
||||
// Zero-hop broadcast (hop_limit == hop_start): should be allowed
|
||||
static void test_zeroHopBroadcast_isAllowed()
|
||||
{
|
||||
testPacket.to = NODENUM_BROADCAST;
|
||||
testPacket.hop_start = 3;
|
||||
testPacket.hop_limit = 3; // Not yet relayed
|
||||
|
||||
TEST_ASSERT_FALSE(testModule->isMultiHopBroadcastRequest());
|
||||
}
|
||||
|
||||
// Multi-hop broadcast (hop_limit < hop_start): should be blocked
|
||||
static void test_multiHopBroadcast_isBlocked()
|
||||
{
|
||||
testPacket.to = NODENUM_BROADCAST;
|
||||
testPacket.hop_start = 7;
|
||||
testPacket.hop_limit = 4; // Already relayed 3 hops
|
||||
|
||||
TEST_ASSERT_TRUE(testModule->isMultiHopBroadcastRequest());
|
||||
}
|
||||
|
||||
// Direct message (not broadcast): should always be allowed regardless of hops
|
||||
static void test_directMessage_isAllowed()
|
||||
{
|
||||
testPacket.to = 0x12345678; // Specific node
|
||||
testPacket.hop_start = 7;
|
||||
testPacket.hop_limit = 4;
|
||||
|
||||
TEST_ASSERT_FALSE(testModule->isMultiHopBroadcastRequest());
|
||||
}
|
||||
|
||||
// Broadcast with hop_limit == 0 (fully relayed): should be blocked
|
||||
static void test_fullyRelayedBroadcast_isBlocked()
|
||||
{
|
||||
testPacket.to = NODENUM_BROADCAST;
|
||||
testPacket.hop_start = 3;
|
||||
testPacket.hop_limit = 0;
|
||||
|
||||
TEST_ASSERT_TRUE(testModule->isMultiHopBroadcastRequest());
|
||||
}
|
||||
|
||||
// No current request: should not crash, should return false
|
||||
static void test_noCurrentRequest_isAllowed()
|
||||
{
|
||||
TestModule::currentRequest = NULL;
|
||||
|
||||
TEST_ASSERT_FALSE(testModule->isMultiHopBroadcastRequest());
|
||||
}
|
||||
|
||||
// Broadcast with hop_start == 0 (legacy or local): should be allowed
|
||||
static void test_legacyPacket_zeroHopStart_isAllowed()
|
||||
{
|
||||
testPacket.to = NODENUM_BROADCAST;
|
||||
testPacket.hop_start = 0;
|
||||
testPacket.hop_limit = 0;
|
||||
|
||||
// hop_limit == hop_start, so not multi-hop
|
||||
TEST_ASSERT_FALSE(testModule->isMultiHopBroadcastRequest());
|
||||
}
|
||||
|
||||
// Single hop relayed broadcast (hop_limit = hop_start - 1): should be blocked
|
||||
static void test_singleHopRelayedBroadcast_isBlocked()
|
||||
{
|
||||
testPacket.to = NODENUM_BROADCAST;
|
||||
testPacket.hop_start = 3;
|
||||
testPacket.hop_limit = 2;
|
||||
|
||||
TEST_ASSERT_TRUE(testModule->isMultiHopBroadcastRequest());
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
initializeTestEnvironment();
|
||||
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_zeroHopBroadcast_isAllowed);
|
||||
RUN_TEST(test_multiHopBroadcast_isBlocked);
|
||||
RUN_TEST(test_directMessage_isAllowed);
|
||||
RUN_TEST(test_fullyRelayedBroadcast_isBlocked);
|
||||
RUN_TEST(test_noCurrentRequest_isAllowed);
|
||||
RUN_TEST(test_legacyPacket_zeroHopStart_isAllowed);
|
||||
RUN_TEST(test_singleHopRelayedBroadcast_isBlocked);
|
||||
exit(UNITY_END());
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
Reference in New Issue
Block a user