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. */
|
/* We allow modules to ignore a request without sending an error if they have a specific reason for it. */
|
||||||
bool ignoreRequest = false;
|
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.
|
/** 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
|
* 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).
|
* 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()
|
meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply()
|
||||||
{
|
{
|
||||||
if (currentRequest) {
|
if (currentRequest) {
|
||||||
|
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||||
|
ignoreRequest = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
auto req = *currentRequest;
|
auto req = *currentRequest;
|
||||||
const auto &p = req.decoded;
|
const auto &p = req.decoded;
|
||||||
meshtastic_Telemetry scratch;
|
meshtastic_Telemetry scratch;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseTelemetryModule.h"
|
||||||
|
|
||||||
#ifndef AIR_QUALITY_TELEMETRY_MODULE_ENABLE
|
#ifndef AIR_QUALITY_TELEMETRY_MODULE_ENABLE
|
||||||
#define AIR_QUALITY_TELEMETRY_MODULE_ENABLE 0
|
#define AIR_QUALITY_TELEMETRY_MODULE_ENABLE 0
|
||||||
#endif
|
#endif
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
|
|
||||||
class AirQualityTelemetryModule : private concurrency::OSThread,
|
class AirQualityTelemetryModule : private concurrency::OSThread,
|
||||||
public ScanI2CConsumer,
|
public ScanI2CConsumer,
|
||||||
|
public BaseTelemetryModule,
|
||||||
public ProtobufModule<meshtastic_Telemetry>
|
public ProtobufModule<meshtastic_Telemetry>
|
||||||
{
|
{
|
||||||
CallbackObserver<AirQualityTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
CallbackObserver<AirQualityTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||||
|
|||||||
@@ -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()
|
int32_t DeviceTelemetryModule::runOnce()
|
||||||
{
|
{
|
||||||
refreshUptime();
|
refreshUptime();
|
||||||
bool isImpoliteRole =
|
bool isImpoliteRole = isSensorOrRouterRole();
|
||||||
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_ROUTER);
|
|
||||||
if (((lastSentToMesh == 0) ||
|
if (((lastSentToMesh == 0) ||
|
||||||
((uptimeLastMs - lastSentToMesh) >=
|
((uptimeLastMs - lastSentToMesh) >=
|
||||||
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
||||||
@@ -60,6 +59,10 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
|
|||||||
meshtastic_MeshPacket *DeviceTelemetryModule::allocReply()
|
meshtastic_MeshPacket *DeviceTelemetryModule::allocReply()
|
||||||
{
|
{
|
||||||
if (currentRequest) {
|
if (currentRequest) {
|
||||||
|
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||||
|
ignoreRequest = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
auto req = *currentRequest;
|
auto req = *currentRequest;
|
||||||
const auto &p = req.decoded;
|
const auto &p = req.decoded;
|
||||||
meshtastic_Telemetry scratch;
|
meshtastic_Telemetry scratch;
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "BaseTelemetryModule.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
#include <OLEDDisplayUi.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 *> nodeStatusObserver =
|
||||||
CallbackObserver<DeviceTelemetryModule, const meshtastic::Status *>(this, &DeviceTelemetryModule::handleStatusUpdate);
|
CallbackObserver<DeviceTelemetryModule, const meshtastic::Status *>(this, &DeviceTelemetryModule::handleStatusUpdate);
|
||||||
|
|||||||
@@ -577,6 +577,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
|||||||
meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply()
|
meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply()
|
||||||
{
|
{
|
||||||
if (currentRequest) {
|
if (currentRequest) {
|
||||||
|
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||||
|
ignoreRequest = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
auto req = *currentRequest;
|
auto req = *currentRequest;
|
||||||
const auto &p = req.decoded;
|
const auto &p = req.decoded;
|
||||||
meshtastic_Telemetry scratch;
|
meshtastic_Telemetry scratch;
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseTelemetryModule.h"
|
||||||
|
|
||||||
#ifndef ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE
|
#ifndef ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE
|
||||||
#define ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE 0
|
#define ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE 0
|
||||||
#endif
|
#endif
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
|
|
||||||
class EnvironmentTelemetryModule : private concurrency::OSThread,
|
class EnvironmentTelemetryModule : private concurrency::OSThread,
|
||||||
public ScanI2CConsumer,
|
public ScanI2CConsumer,
|
||||||
|
public BaseTelemetryModule,
|
||||||
public ProtobufModule<meshtastic_Telemetry>
|
public ProtobufModule<meshtastic_Telemetry>
|
||||||
{
|
{
|
||||||
CallbackObserver<EnvironmentTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
CallbackObserver<EnvironmentTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||||
|
|||||||
@@ -192,6 +192,10 @@ bool HealthTelemetryModule::getHealthTelemetry(meshtastic_Telemetry *m)
|
|||||||
meshtastic_MeshPacket *HealthTelemetryModule::allocReply()
|
meshtastic_MeshPacket *HealthTelemetryModule::allocReply()
|
||||||
{
|
{
|
||||||
if (currentRequest) {
|
if (currentRequest) {
|
||||||
|
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||||
|
ignoreRequest = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
auto req = *currentRequest;
|
auto req = *currentRequest;
|
||||||
const auto &p = req.decoded;
|
const auto &p = req.decoded;
|
||||||
meshtastic_Telemetry scratch;
|
meshtastic_Telemetry scratch;
|
||||||
|
|||||||
@@ -4,12 +4,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "BaseTelemetryModule.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
#include <OLEDDisplayUi.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 *> nodeStatusObserver =
|
||||||
CallbackObserver<HealthTelemetryModule, const meshtastic::Status *>(this, &HealthTelemetryModule::handleStatusUpdate);
|
CallbackObserver<HealthTelemetryModule, const meshtastic::Status *>(this, &HealthTelemetryModule::handleStatusUpdate);
|
||||||
|
|||||||
@@ -217,6 +217,10 @@ bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m)
|
|||||||
meshtastic_MeshPacket *PowerTelemetryModule::allocReply()
|
meshtastic_MeshPacket *PowerTelemetryModule::allocReply()
|
||||||
{
|
{
|
||||||
if (currentRequest) {
|
if (currentRequest) {
|
||||||
|
if (isMultiHopBroadcastRequest() && !isSensorOrRouterRole()) {
|
||||||
|
ignoreRequest = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
auto req = *currentRequest;
|
auto req = *currentRequest;
|
||||||
const auto &p = req.decoded;
|
const auto &p = req.decoded;
|
||||||
meshtastic_Telemetry scratch;
|
meshtastic_Telemetry scratch;
|
||||||
|
|||||||
@@ -5,12 +5,15 @@
|
|||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "BaseTelemetryModule.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
#include <OLEDDisplay.h>
|
#include <OLEDDisplay.h>
|
||||||
#include <OLEDDisplayUi.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 *> nodeStatusObserver =
|
||||||
CallbackObserver<PowerTelemetryModule, const meshtastic::Status *>(this, &PowerTelemetryModule::handleStatusUpdate);
|
CallbackObserver<PowerTelemetryModule, const meshtastic::Status *>(this, &PowerTelemetryModule::handleStatusUpdate);
|
||||||
|
|||||||
@@ -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