Initial version of NextHopRouter

pull/2856/head
GUVWAF 2023-10-02 19:31:23 +02:00
rodzic a6e4402e41
commit 0d6729b9eb
20 zmienionych plików z 316 dodań i 36 usunięć

Wyświetl plik

@ -561,6 +561,9 @@ void setup()
}
nodeStatus->observe(&nodeDB.newStatus);
config.lora.next_hop_routing = true; // FIXME - remove this before merging
LOG_INFO("USING NEXT-HOP ROUTING\n");
service.init();
// Now that the mesh service is created, create any modules

Wyświetl plik

@ -71,4 +71,4 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
}
// handle the packet as normal
Router::sniffReceived(p, c);
}
}

Wyświetl plik

@ -0,0 +1,106 @@
#include "NextHopRouter.h"
NextHopRouter::NextHopRouter() {}
/**
* Send a packet
*/
ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p)
{
// Add any messages _we_ send to the seen message list (so we will ignore all retransmissions we see)
wasSeenRecently(p); // FIXME, move this to a sniffSent method
p->next_hop = getNextHop(p->to, p->current_relayer); // set the next hop
LOG_DEBUG("Setting next hop for packet with dest %x to %x\n", p->to, p->next_hop);
return Router::send(p);
}
bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
{
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
if (p->next_hop == getNodeNum()) {
LOG_DEBUG("Ignoring incoming msg, because we've already seen it.\n");
} else {
LOG_DEBUG("Ignoring incoming msg, because we've already seen it and cancel any outgoing packets.\n");
Router::cancelSending(p->from, p->id);
}
return true;
}
return Router::shouldFilterReceived(p);
}
void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{
bool isAck =
((c && c->error_reason == meshtastic_Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK
if (isAck) {
// Update next-hop of this successful transmission to current relayer, but ONLY if "from" is not 0 or ourselves (means
// implicit ACK or someone is relaying our ACK)
if (p->from != 0 && p->from != getNodeNum()) {
if (p->current_relayer) {
meshtastic_NodeInfoLite *sentTo = nodeDB.getMeshNode(p->from);
if (sentTo) {
LOG_DEBUG("Update next hop of %x to %x based on received ACK.\n", p->from, p->current_relayer);
sentTo->next_hop = p->current_relayer;
}
}
}
}
if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) {
if ((p->to != getNodeNum()) && (getFrom(p) != getNodeNum())) {
if (p->next_hop == getNodeNum()) {
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
LOG_INFO("Relaying received next-hop message coming from %x\n", p->current_relayer);
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
// If it is a traceRoute request, update the route that it went via me
if (traceRouteModule && traceRouteModule->wantPacket(tosend))
traceRouteModule->updateRoute(tosend);
// If it is a neighborInfo packet, update last_sent_by_id
if (neighborInfoModule && neighborInfoModule->wantPacket(tosend))
neighborInfoModule->updateLastSentById(tosend);
}
tosend->hop_limit--; // bump down the hop count
NextHopRouter::send(tosend);
} else if (p->next_hop == 0) {
// No preference for next hop, use FloodingRouter
LOG_DEBUG("No preference for next hop, using FloodingRouter\n");
FloodingRouter::sniffReceived(p, c);
} else if (p->to == NODENUM_BROADCAST) {
// TODO how to handle broadcast messages?
LOG_DEBUG("TODO: Broadcast next-hop message\n");
FloodingRouter::sniffReceived(p, c);
}
}
} else {
LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n");
}
// handle the packet as normal
Router::sniffReceived(p, c);
}
/**
* Get the next hop for a destination, given the current relayer
* @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter)
*/
uint32_t NextHopRouter::getNextHop(NodeNum to, NodeNum current_relayer)
{
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(to);
if (node) {
// We are careful not to return the current relayer as the next hop
if (node->next_hop != current_relayer) {
LOG_DEBUG("Next hop for %x is %x\n", to, node->next_hop);
return node->next_hop;
} else {
LOG_WARN("Next hop for %x is %x, which is the same as current relayer; setting as no preference\n", to,
node->next_hop);
return 0;
}
} else {
return 0;
}
}

Wyświetl plik

@ -0,0 +1,49 @@
#pragma once
#include "FloodingRouter.h"
/*
Router which only relays if it is the next hop for a packet.
The next hop is set by the current relayer of a packet, which bases this on information from either the NeighborInfoModule, or a
previous successful delivery via flooding. It is only used for DMs and not used for broadcasts. Using the NeighborInfoModule, it
can derive the next hop of neighbors and that of neighbors of neighbors. For others, it has no information in the beginning,
which results into falling back to the FloodingRouter. Upon successful delivery via flooding, it updates the next hop of the
recipient to the node that last relayed the ACK to us. When the ReliableRouter is doing retransmissions, at the last retry, it
will reset the next hop, in order to fall back to the FloodingRouter.
*/
class NextHopRouter : public FloodingRouter
{
public:
/**
* Constructor
*
*/
NextHopRouter();
/**
* Send a packet
* @return an error code
*/
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
protected:
/**
* Should this incoming filter be dropped?
*
* Called immediately on reception, before any further processing.
* @return true to abandon the packet
*/
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override;
/**
* Look for packets we need to relay
*/
virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override;
private:
/**
* Get the next hop for a destination, given the current relayer
* @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter)
*/
uint32_t getNextHop(NodeNum to, NodeNum current_relayer);
};

Wyświetl plik

@ -814,6 +814,16 @@ meshtastic_NodeInfoLite *NodeDB::getMeshNode(NodeNum n)
return NULL;
}
// Find a node in the database that matches the last byte, return 0 if not found
NodeNum NodeDB::findMatchingNodeNum(uint8_t last_byte)
{
for (int i = 0; i < *numMeshNodes; i++)
if ((uint8_t)(meshNodes[i].num & 0xFF) == last_byte)
return meshNodes[i].num;
return 0;
}
/// Find a node in our DB, create an empty NodeInfo if missing
meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
{

Wyświetl plik

@ -129,6 +129,7 @@ class NodeDB
}
meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
NodeNum findMatchingNodeNum(uint8_t last_byte);
size_t getNumMeshNodes() { return *numMeshNodes; }
private:
@ -242,4 +243,4 @@ extern uint32_t error_address;
#define Module_Config_size \
(ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)

Wyświetl plik

@ -538,6 +538,8 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
p->hop_limit = HOP_RELIABLE;
}
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0);
h->next_hop = (p->next_hop & 0xFF); // set last byte of next_hop
h->current_relayer = (p->current_relayer & 0xFF); // set last byte of current_relayer
// if the sender nodenum is zero, that means uninitialized
assert(h->from);
@ -546,4 +548,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
sendingPacket = p;
return p->encrypted.size + sizeof(PacketHeader);
}
}

Wyświetl plik

@ -31,6 +31,12 @@ typedef struct {
/** The channel hash - used as a hint for the decoder to limit which channels we consider */
uint8_t channel;
// Last byte of the NodeNum of the next-hop for this packet
uint8_t next_hop;
// Last byte of the NodeNum of the current relayer of this packet
uint8_t current_relayer;
} PacketHeader;
/**
@ -223,4 +229,4 @@ class RadioInterface
};
/// Debug printing for packets
void printPacket(const char *prefix, const meshtastic_MeshPacket *p);
void printPacket(const char *prefix, const meshtastic_MeshPacket *p);

Wyświetl plik

@ -362,6 +362,8 @@ void RadioLibInterface::handleReceiveInterrupt()
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
mp->next_hop = nodeDB.findMatchingNodeNum(h->next_hop);
mp->current_relayer = nodeDB.findMatchingNodeNum(h->current_relayer);
addReceiveMetadata(mp);

Wyświetl plik

@ -33,7 +33,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
}
}
return FloodingRouter::send(p);
return config.lora.next_hop_routing ? NextHopRouter::send(p) : FloodingRouter::send(p);
}
bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
@ -71,11 +71,11 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
i->second.nextTxMsec += iface->getPacketTime(p);
}
/* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE)
/* Resend implicit ACKs for repeated packets (current relayer is the same as original transmitter)
* this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
* flooding this ACK back to the original sender already adds redundancy. */
if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
if (wasSeenRecently(p, false) && p->current_relayer == p->from && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n");
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p);
@ -83,7 +83,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
Router::send(tosend);
}
return FloodingRouter::shouldFilterReceived(p);
return config.lora.next_hop_routing ? NextHopRouter::shouldFilterReceived(p) : FloodingRouter::shouldFilterReceived(p);
}
/**
@ -133,7 +133,7 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
}
// handle the packet as normal
FloodingRouter::sniffReceived(p, c);
config.lora.next_hop_routing ? NextHopRouter::sniffReceived(p, c) : FloodingRouter::sniffReceived(p, c);
}
#define NUM_RETRANSMISSIONS 3
@ -222,9 +222,21 @@ int32_t ReliableRouter::doRetransmissions()
LOG_DEBUG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from,
p.packet->to, p.packet->id, p.numRetransmissions);
if (config.lora.next_hop_routing && p.numRetransmissions == 1) {
// Last retransmission, reset next_hop (fallback to FloodingRouter)
p.packet->next_hop = 0;
// Also reset it in the nodeDB
meshtastic_NodeInfoLite *sentTo = nodeDB.getMeshNode(p.packet->to);
if (sentTo) {
LOG_DEBUG("Resetting next hop for packet with dest %x\n", p.packet->to);
sentTo->next_hop = 0;
}
}
// Note: we call the superclass version because we don't want to have our version of send() add a new
// retransmission record
FloodingRouter::send(packetPool.allocCopy(*p.packet));
config.lora.next_hop_routing ? NextHopRouter::send(packetPool.allocCopy(*p.packet))
: FloodingRouter::send(packetPool.allocCopy(*p.packet));
// Queue again
--p.numRetransmissions;
@ -251,4 +263,4 @@ void ReliableRouter::setNextTx(PendingPacket *pending)
LOG_DEBUG("Setting next retransmission in %u msecs: ", d);
printPacket("", pending->packet);
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
}
}

Wyświetl plik

@ -1,6 +1,6 @@
#pragma once
#include "FloodingRouter.h"
#include "NextHopRouter.h"
#include <unordered_map>
/**
@ -51,7 +51,7 @@ class GlobalPacketIdHashFunction
/**
* This is a mixin that extends Router with the ability to do (one hop only) reliable message sends.
*/
class ReliableRouter : public FloodingRouter
class ReliableRouter : public NextHopRouter
{
private:
std::unordered_map<GlobalPacketId, PendingPacket, GlobalPacketIdHashFunction> pending;
@ -120,4 +120,4 @@ class ReliableRouter : public FloodingRouter
int32_t doRetransmissions();
void setNextTx(PendingPacket *pending);
};
};

Wyświetl plik

@ -240,6 +240,8 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
// the lora we need to make sure we have replaced it with our local address
p->from = getFrom(p);
p->current_relayer = getNodeNum(); // set the current relayer to us
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag ||

Wyświetl plik

@ -54,7 +54,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg;
#define meshtastic_ChannelSet_fields &meshtastic_ChannelSet_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_ChannelSet_size 591
#define meshtastic_ChannelSet_size 593
#ifdef __cplusplus
} /* extern "C" */

Wyświetl plik

@ -438,6 +438,8 @@ typedef struct _meshtastic_Config_LoRaConfig {
Please respect your local laws and regulations. If you are a HAM, make sure you
enable HAM mode and turn off encryption. */
float override_frequency;
/* If the NeighborInfo Module is enabled, use its information for next hop-based routing */
bool next_hop_routing;
/* For testing it is useful sometimes to force a node to never listen to
particular other nodes (simulating radio out of range). All nodenums listed
in ignore_incoming will have packets they send dropped on receive (by router.cpp) */
@ -545,7 +547,7 @@ extern "C" {
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0}
@ -554,7 +556,7 @@ extern "C" {
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0}
#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
/* Field tags (for use in manual encoding/decoding) */
@ -624,6 +626,7 @@ extern "C" {
#define meshtastic_Config_LoRaConfig_override_duty_cycle_tag 12
#define meshtastic_Config_LoRaConfig_sx126x_rx_boosted_gain_tag 13
#define meshtastic_Config_LoRaConfig_override_frequency_tag 14
#define meshtastic_Config_LoRaConfig_next_hop_routing_tag 15
#define meshtastic_Config_LoRaConfig_ignore_incoming_tag 103
#define meshtastic_Config_BluetoothConfig_enabled_tag 1
#define meshtastic_Config_BluetoothConfig_mode_tag 2
@ -747,6 +750,7 @@ X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \
X(a, STATIC, SINGULAR, BOOL, override_duty_cycle, 12) \
X(a, STATIC, SINGULAR, BOOL, sx126x_rx_boosted_gain, 13) \
X(a, STATIC, SINGULAR, FLOAT, override_frequency, 14) \
X(a, STATIC, SINGULAR, BOOL, next_hop_routing, 15) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
#define meshtastic_Config_LoRaConfig_CALLBACK NULL
#define meshtastic_Config_LoRaConfig_DEFAULT NULL
@ -783,7 +787,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
#define meshtastic_Config_BluetoothConfig_size 10
#define meshtastic_Config_DeviceConfig_size 32
#define meshtastic_Config_DisplayConfig_size 28
#define meshtastic_Config_LoRaConfig_size 77
#define meshtastic_Config_LoRaConfig_size 79
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
#define meshtastic_Config_NetworkConfig_size 195
#define meshtastic_Config_PositionConfig_size 60

Wyświetl plik

@ -65,6 +65,8 @@ typedef struct _meshtastic_NodeInfoLite {
meshtastic_DeviceMetrics device_metrics;
/* local channel index we heard that node on. Only populated if its not the default channel. */
uint8_t channel;
/* Node number of the node to use as a next hop in order to reach this node. */
uint32_t next_hop;
} meshtastic_NodeInfoLite;
/* The on-disk saved channels */
@ -175,13 +177,13 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_init_default, 0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}, 0, {meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default, meshtastic_NodeInfoLite_init_default}}
#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_User_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0}
#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_User_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0}
#define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN}
#define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0}
#define meshtastic_OEMStore_init_default {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default}
#define meshtastic_NodeRemoteHardwarePin_init_default {0, false, meshtastic_RemoteHardwarePin_init_default}
#define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_init_zero, 0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}, 0, {meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero, meshtastic_NodeInfoLite_init_zero}}
#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0}
#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0}
#define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN}
#define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0}
#define meshtastic_OEMStore_init_zero {0, 0, {0, {0}}, _meshtastic_ScreenFonts_MIN, "", {0, {0}}, false, meshtastic_LocalConfig_init_zero, false, meshtastic_LocalModuleConfig_init_zero}
@ -200,6 +202,7 @@ extern "C" {
#define meshtastic_NodeInfoLite_last_heard_tag 5
#define meshtastic_NodeInfoLite_device_metrics_tag 6
#define meshtastic_NodeInfoLite_channel_tag 7
#define meshtastic_NodeInfoLite_next_hop_tag 8
#define meshtastic_ChannelFile_channels_tag 1
#define meshtastic_ChannelFile_version_tag 2
#define meshtastic_OEMStore_oem_icon_width_tag 1
@ -252,7 +255,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, position, 3) \
X(a, STATIC, SINGULAR, FLOAT, snr, 4) \
X(a, STATIC, SINGULAR, FIXED32, last_heard, 5) \
X(a, STATIC, OPTIONAL, MESSAGE, device_metrics, 6) \
X(a, STATIC, SINGULAR, UINT32, channel, 7)
X(a, STATIC, SINGULAR, UINT32, channel, 7) \
X(a, STATIC, SINGULAR, UINT32, next_hop, 8)
#define meshtastic_NodeInfoLite_CALLBACK NULL
#define meshtastic_NodeInfoLite_DEFAULT NULL
#define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_User
@ -313,10 +317,10 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_ChannelFile_size 638
#define meshtastic_DeviceState_size 16854
#define meshtastic_NodeInfoLite_size 151
#define meshtastic_DeviceState_size 17490
#define meshtastic_NodeInfoLite_size 157
#define meshtastic_NodeRemoteHardwarePin_size 29
#define meshtastic_OEMStore_size 3218
#define meshtastic_OEMStore_size 3220
#define meshtastic_PositionLite_size 28
#ifdef __cplusplus

Wyświetl plik

@ -174,7 +174,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_LocalConfig_size 463
#define meshtastic_LocalConfig_size 465
#define meshtastic_LocalModuleConfig_size 609
#ifdef __cplusplus

Wyświetl plik

@ -563,6 +563,12 @@ typedef struct _meshtastic_MeshPacket {
int32_t rx_rssi;
/* Describe if this message is delayed */
meshtastic_MeshPacket_Delayed delayed;
/* Node number of the node that should be used as the next hop in routing.
Only the last byte is sent in the packet header. */
uint32_t next_hop;
/* Node number of the node that is currently relaying this packet.
Only the last byte is sent in the packet header. */
uint32_t current_relayer;
} meshtastic_MeshPacket;
/* The bluetooth to device link:
@ -686,7 +692,7 @@ typedef struct _meshtastic_Neighbor {
uint32_t node_id;
/* SNR of last heard message */
float snr;
/* Reception time (in secs since 1970) of last message that was last sent by this ID.
/* Reception time of last message that was sent by this ID.
Note: this is for local storage only and will not be sent out over the mesh. */
uint32_t last_rx_time;
/* Broadcast interval of this neighbor (in seconds).
@ -858,7 +864,7 @@ extern "C" {
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
#define meshtastic_Waypoint_init_default {0, 0, 0, 0, 0, "", "", 0}
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN}
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0}
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0}
#define meshtastic_MyNodeInfo_init_default {0, 0, 0}
#define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN}
@ -876,7 +882,7 @@ extern "C" {
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
#define meshtastic_Waypoint_init_zero {0, 0, 0, 0, 0, "", "", 0}
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN}
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0}
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0}
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0}
#define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN}
@ -954,6 +960,8 @@ extern "C" {
#define meshtastic_MeshPacket_priority_tag 11
#define meshtastic_MeshPacket_rx_rssi_tag 12
#define meshtastic_MeshPacket_delayed_tag 13
#define meshtastic_MeshPacket_next_hop_tag 14
#define meshtastic_MeshPacket_current_relayer_tag 15
#define meshtastic_NodeInfo_num_tag 1
#define meshtastic_NodeInfo_user_tag 2
#define meshtastic_NodeInfo_position_tag 3
@ -1108,7 +1116,9 @@ X(a, STATIC, SINGULAR, UINT32, hop_limit, 9) \
X(a, STATIC, SINGULAR, BOOL, want_ack, 10) \
X(a, STATIC, SINGULAR, UENUM, priority, 11) \
X(a, STATIC, SINGULAR, INT32, rx_rssi, 12) \
X(a, STATIC, SINGULAR, UENUM, delayed, 13)
X(a, STATIC, SINGULAR, UENUM, delayed, 13) \
X(a, STATIC, SINGULAR, UINT32, next_hop, 14) \
X(a, STATIC, SINGULAR, UINT32, current_relayer, 15)
#define meshtastic_MeshPacket_CALLBACK NULL
#define meshtastic_MeshPacket_DEFAULT NULL
#define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data
@ -1209,7 +1219,7 @@ X(a, STATIC, REPEATED, MESSAGE, neighbors, 4)
#define meshtastic_Neighbor_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, node_id, 1) \
X(a, STATIC, SINGULAR, FLOAT, snr, 2) \
X(a, STATIC, SINGULAR, FIXED32, last_rx_time, 3) \
X(a, STATIC, SINGULAR, UINT32, last_rx_time, 3) \
X(a, STATIC, SINGULAR, UINT32, node_broadcast_interval_secs, 4)
#define meshtastic_Neighbor_CALLBACK NULL
#define meshtastic_Neighbor_DEFAULT NULL
@ -1273,11 +1283,11 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
#define meshtastic_DeviceMetadata_size 46
#define meshtastic_FromRadio_size 510
#define meshtastic_LogRecord_size 81
#define meshtastic_MeshPacket_size 321
#define meshtastic_MeshPacket_size 333
#define meshtastic_MqttClientProxyMessage_size 501
#define meshtastic_MyNodeInfo_size 18
#define meshtastic_NeighborInfo_size 258
#define meshtastic_Neighbor_size 22
#define meshtastic_NeighborInfo_size 268
#define meshtastic_Neighbor_size 23
#define meshtastic_NodeInfo_size 261
#define meshtastic_Position_size 137
#define meshtastic_QueueStatus_size 23

Wyświetl plik

@ -156,6 +156,17 @@ size_t NeighborInfoModule::cleanUpNeighbors()
// Update the neighbor list
for (uint i = 0; i < indices_to_remove.size(); i++) {
int index = indices_to_remove[i];
if (config.lora.next_hop_routing) {
// Clear all next hops of nodes that had this neighbor as next hop
for (unsigned int j = 0; j < nodeDB.getNumMeshNodes(); j++) {
meshtastic_NodeInfoLite *node = nodeDB.getMeshNodeByIndex(j);
if (node->next_hop == neighbors[index].node_id) {
node->next_hop = 0;
}
}
}
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", neighbors[index].node_id);
for (int j = index; j < num_neighbors - 1; j++) {
neighbors[j] = neighbors[j + 1];
@ -205,6 +216,8 @@ bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp,
if (enabled) {
printNeighborInfo("RECEIVED", np);
updateNeighbors(mp, np);
if (config.lora.next_hop_routing)
updateNextHops(np);
}
// Allow others to handle this packet
return false;
@ -229,6 +242,54 @@ void NeighborInfoModule::updateLastSentById(meshtastic_MeshPacket *p)
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_NeighborInfo_msg, updated);
}
/* Update the next hop for nodes in the database.
* Based on our own neighbors, and the neighbors of our neighbors.
*/
void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np)
{
LOG_DEBUG("Updating next hops based on received NeighborInfo packet\n");
meshtastic_NodeInfoLite *currentNode = nodeDB.getMeshNode(np->node_id);
// Check if the sender of this neighborInfo packet is a neighbor of ourselves
if (currentNode && isANeighbor(np->node_id)) {
currentNode->next_hop = np->node_id; // Set the next hop to the sender of this packet
for (uint8_t i = 0; i < np->neighbors_count; i++) {
if (isANeighbor(np->neighbors[i].node_id))
continue; // This node is a neighbor of ourselves
meshtastic_NodeInfoLite *neighborOfCurrentNode = nodeDB.getMeshNode(np->neighbors[i].node_id);
// Update next hop of this node to the sender of this packet, because it is the most recent neighbor
if (neighborOfCurrentNode)
neighborOfCurrentNode->next_hop = currentNode->num;
}
} else if (currentNode) { // Sender is not a neighbor
// Find common neighbors and use the most recent as next hop to this node
meshtastic_NodeInfoLite *currentNextHop = nodeDB.getMeshNode(currentNode->next_hop);
uint32_t maxLastHeard = currentNextHop ? currentNextHop->last_heard : 0;
for (uint8_t i = 0; i < np->neighbors_count; i++) {
meshtastic_NodeInfoLite *neighborOfCurrentNode = nodeDB.getMeshNode(np->neighbors[i].node_id);
if (neighborOfCurrentNode && isANeighbor(neighborOfCurrentNode->num)) {
// This neighbor was heard more recently than the current next hop
if (neighborOfCurrentNode->last_heard > maxLastHeard) {
currentNode->next_hop = neighborOfCurrentNode->num;
maxLastHeard = neighborOfCurrentNode->last_heard;
LOG_DEBUG("More recent node found, so update next_hop of %x to %x\n", currentNode->num,
neighborOfCurrentNode->num);
}
}
}
}
}
bool NeighborInfoModule::isANeighbor(NodeNum node_id)
{
for (int i = 0; i < *numNeighbors; i++) {
if (neighbors[i].node_id == node_id) {
return true;
}
}
return false;
}
void NeighborInfoModule::resetNeighbors()
{
*numNeighbors = 0;
@ -308,4 +369,4 @@ bool NeighborInfoModule::saveProtoForModule()
okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState);
return okay;
}
}

Wyświetl plik

@ -20,8 +20,9 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
bool saveProtoForModule();
// Let FloodingRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet
// Let FloodingRouter/NexthopRouter call updateLastSentById upon rebroadcasting a NeighborInfo packet
friend class FloodingRouter;
friend class NextHopRouter;
protected:
// Note: this holds our local info.
@ -70,6 +71,12 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
/* update a NeighborInfo packet with our NodeNum as last_sent_by_id */
void updateLastSentById(meshtastic_MeshPacket *p);
/* update the next hop for nodes in the database */
void updateNextHops(meshtastic_NeighborInfo *np);
/* check if the given node number is a neighbor of us */
bool isANeighbor(NodeNum node_id);
void loadProtoForModule();
/* Does our periodic broadcast */

Wyświetl plik

@ -9,8 +9,9 @@ class TraceRouteModule : public ProtobufModule<meshtastic_RouteDiscovery>
public:
TraceRouteModule();
// Let FloodingRouter call updateRoute upon rebroadcasting a TraceRoute request
// Let FloodingRouter/NextHopRouter call updateRoute upon rebroadcasting a TraceRoute request
friend class FloodingRouter;
friend class NextHopRouter;
protected:
bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_RouteDiscovery *r) override;