From 0d6729b9eb84394d3e0b5680fbb5fccc97f5a097 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Mon, 2 Oct 2023 19:31:23 +0200 Subject: [PATCH 01/32] Initial version of NextHopRouter --- src/main.cpp | 3 + src/mesh/FloodingRouter.cpp | 2 +- src/mesh/NextHopRouter.cpp | 106 ++++++++++++++++++ src/mesh/NextHopRouter.h | 49 ++++++++ src/mesh/NodeDB.cpp | 10 ++ src/mesh/NodeDB.h | 3 +- src/mesh/RadioInterface.cpp | 4 +- src/mesh/RadioInterface.h | 8 +- src/mesh/RadioLibInterface.cpp | 2 + src/mesh/ReliableRouter.cpp | 26 +++-- src/mesh/ReliableRouter.h | 6 +- src/mesh/Router.cpp | 2 + src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/config.pb.h | 10 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 16 ++- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 26 +++-- src/modules/NeighborInfoModule.cpp | 63 ++++++++++- src/modules/NeighborInfoModule.h | 9 +- src/modules/TraceRouteModule.h | 3 +- 20 files changed, 316 insertions(+), 36 deletions(-) create mode 100644 src/mesh/NextHopRouter.cpp create mode 100644 src/mesh/NextHopRouter.h diff --git a/src/main.cpp b/src/main.cpp index a4caad3fd9..d2a91a47bd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index d27d47e875..d0061ed8aa 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -71,4 +71,4 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas } // handle the packet as normal Router::sniffReceived(p, c); -} \ No newline at end of file +} diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp new file mode 100644 index 0000000000..9cacda5fc3 --- /dev/null +++ b/src/mesh/NextHopRouter.cpp @@ -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; + } +} \ No newline at end of file diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h new file mode 100644 index 0000000000..2746886f40 --- /dev/null +++ b/src/mesh/NextHopRouter.h @@ -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); +}; \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index d7fd84fb7f..cfa42c4d98 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -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) { diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index f906acd589..52523b7a67 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -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) \ No newline at end of file diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 0d22383965..3f8fadd2a6 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -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); -} +} \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 9c5d66293b..450d607095 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -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); \ No newline at end of file diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 4f0c52e678..fedc475adb 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -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); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 946a669cc0..d4310b873b 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -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 -} +} \ No newline at end of file diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index 259da7249f..c5ceff73bd 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -1,6 +1,6 @@ #pragma once -#include "FloodingRouter.h" +#include "NextHopRouter.h" #include /** @@ -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 pending; @@ -120,4 +120,4 @@ class ReliableRouter : public FloodingRouter int32_t doRetransmissions(); void setNextTx(PendingPacket *pending); -}; +}; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 03aa573513..888818c855 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -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 || diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index b66af0ebdf..65093506fb 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -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" */ diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 2a811140fe..22a837242c 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -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 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index c554074a20..2d6269888d 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -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 diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index f672d865c3..44c49d0474 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -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 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index c32f55aabf..110c2217d5 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -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 diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index cf2276f0e4..09e7dd5cb3 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -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; -} \ No newline at end of file +} diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h index 0e3ec09ca3..e848f7ee4d 100644 --- a/src/modules/NeighborInfoModule.h +++ b/src/modules/NeighborInfoModule.h @@ -20,8 +20,9 @@ class NeighborInfoModule : public ProtobufModule, 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, 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 */ diff --git a/src/modules/TraceRouteModule.h b/src/modules/TraceRouteModule.h index 674846ef16..8e8b645612 100644 --- a/src/modules/TraceRouteModule.h +++ b/src/modules/TraceRouteModule.h @@ -9,8 +9,9 @@ class TraceRouteModule : public ProtobufModule 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; From 44dc270c8a72d6af0ebcf55bcfcb060638f691ef Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 13 Oct 2023 21:00:12 +0200 Subject: [PATCH 02/32] Set original hop limit in header flags --- src/mesh/NextHopRouter.cpp | 36 +++++++++---------- src/mesh/NextHopRouter.h | 8 +++-- src/mesh/NodeDB.cpp | 15 +++----- src/mesh/NodeDB.h | 1 - src/mesh/RadioInterface.cpp | 5 +-- src/mesh/RadioInterface.h | 6 ++-- src/mesh/RadioLibInterface.cpp | 5 +-- src/mesh/ReliableRouter.cpp | 16 ++++----- src/mesh/Router.cpp | 6 +++- src/mesh/generated/meshtastic/config.pb.h | 8 ++--- src/mesh/generated/meshtastic/deviceonly.pb.h | 8 ++--- src/mesh/generated/meshtastic/mesh.pb.h | 25 +++++++------ src/mesh/generated/meshtastic/portnums.pb.h | 6 ++-- src/modules/NeighborInfoModule.cpp | 10 +++--- 14 files changed, 77 insertions(+), 78 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 9cacda5fc3..68f4ec6209 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -10,7 +10,7 @@ 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 + p->next_hop = getNextHop(p->to, p->relay_node); // 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); @@ -19,7 +19,7 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *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()) { + if (p->next_hop == (uint8_t)(getNodeNum() & 0xFF)) { 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"); @@ -36,14 +36,14 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast 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 + // Update next-hop of this successful transmission to the relay node, 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) { + if (p->relay_node) { 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; + LOG_DEBUG("Update next hop of 0x%x to 0x%x based on received ACK.\n", p->from, p->relay_node); + sentTo->next_hop = p->relay_node; } } } @@ -51,9 +51,9 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { if ((p->to != getNodeNum()) && (getFrom(p) != getNodeNum())) { - if (p->next_hop == getNodeNum()) { + if (p->next_hop == (uint8_t)(getNodeNum() & 0xFF)) { 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); + LOG_INFO("Relaying received next-hop message coming from %x\n", p->relay_node); if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { // If it is a traceRoute request, update the route that it went via me @@ -71,8 +71,7 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast 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"); + // TODO: Smarter way of handling broadcasts FloodingRouter::sniffReceived(p, c); } } @@ -84,23 +83,22 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast } /** - * Get the next hop for a destination, given the current relayer + * Get the next hop for a destination, given the relay node * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) */ -uint32_t NextHopRouter::getNextHop(NodeNum to, NodeNum current_relayer) +uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node) { 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); + // We are careful not to return the relay node as the next hop + if (node->next_hop != relay_node) { + LOG_DEBUG("Next hop for 0x%x is 0x%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; + LOG_WARN("Next hop for 0x%x is 0x%x, same as relayer; setting as no preference\n", to, node->next_hop); + return NO_NEXT_HOP_PREFERENCE; } } else { - return 0; + return NO_NEXT_HOP_PREFERENCE; } } \ No newline at end of file diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 2746886f40..57b5e68f0c 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -4,7 +4,7 @@ /* 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 + The next hop is set by the relay node 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 @@ -40,10 +40,12 @@ class NextHopRouter : public FloodingRouter */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; + constexpr static uint8_t NO_NEXT_HOP_PREFERENCE = 0; + private: /** - * Get the next hop for a destination, given the current relayer + * Get the next hop for a destination, given the relay node * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) */ - uint32_t getNextHop(NodeNum to, NodeNum current_relayer); + uint8_t getNextHop(NodeNum to, uint8_t relay_node); }; \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index cfa42c4d98..198abdd7ca 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -791,6 +791,11 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) if (mp.decoded.portnum == meshtastic_PortNum_NODEINFO_APP) { info->channel = mp.channel; } + + // If this packet didn't travel any hops, then it was sent directly to us, so we know what to use as next hop to this node + if (mp.original_hop_limit == mp.hop_limit) { + info->next_hop = (uint8_t)(mp.from & 0xFF); + } } } @@ -814,16 +819,6 @@ 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) { diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 52523b7a67..965fae22f3 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -129,7 +129,6 @@ class NodeDB } meshtastic_NodeInfoLite *getMeshNode(NodeNum n); - NodeNum findMatchingNodeNum(uint8_t last_byte); size_t getNumMeshNodes() { return *numMeshNodes; } private: diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 3f8fadd2a6..e128377e32 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -538,8 +538,9 @@ 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 + h->flags |= (p->original_hop_limit & PACKET_FLAGS_HOP_MASK) << PACKET_FLAGS_ORIG_HOP_SHIFT; + h->next_hop = p->next_hop; + h->relay_node = p->relay_node; // if the sender nodenum is zero, that means uninitialized assert(h->from); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 450d607095..fad5ea1d13 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -12,6 +12,8 @@ #define PACKET_FLAGS_HOP_MASK 0x07 #define PACKET_FLAGS_WANT_ACK_MASK 0x08 +#define PACKET_FLAGS_ORIG_HOP_MASK 0x70 +#define PACKET_FLAGS_ORIG_HOP_SHIFT 4 /** * This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility @@ -35,8 +37,8 @@ typedef struct { // 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; + // Last byte of the NodeNum of the node that will relay/relayed this packet + uint8_t relay_node; } PacketHeader; /** diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index fedc475adb..7bbac6ff8c 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -361,9 +361,10 @@ void RadioLibInterface::handleReceiveInterrupt() mp->channel = h->channel; assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK; + mp->original_hop_limit = (h->flags & PACKET_FLAGS_ORIG_HOP_MASK) >> PACKET_FLAGS_ORIG_HOP_SHIFT; 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); + mp->next_hop = h->next_hop; + mp->relay_node = h->relay_node; addReceiveMetadata(mp); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index d4310b873b..70af96d8bd 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -71,11 +71,11 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) i->second.nextTxMsec += iface->getPacketTime(p); } - /* 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->current_relayer == p->from && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) { + /* Resend implicit ACKs for repeated packets (hop limit is the original setting) 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->original_hop_limit == p->hop_limit) && !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); @@ -224,12 +224,12 @@ int32_t ReliableRouter::doRetransmissions() if (config.lora.next_hop_routing && p.numRetransmissions == 1) { // Last retransmission, reset next_hop (fallback to FloodingRouter) - p.packet->next_hop = 0; + p.packet->next_hop = NO_NEXT_HOP_PREFERENCE; // 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; + LOG_DEBUG("Resetting next hop for packet with dest 0x%x\n", p.packet->to); + sentTo->next_hop = NO_NEXT_HOP_PREFERENCE; } } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 888818c855..77b13087cf 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -240,7 +240,11 @@ 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 we are the original transmitter, set the original hop limit + if (p->from == nodeDB.getNodeNum()) + p->original_hop_limit = config.lora.hop_limit ? config.lora.hop_limit : HOP_RELIABLE; + + p->relay_node = (uint8_t)(getNodeNum() & 0xFF); // 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) diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 22a837242c..800d30a04f 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -30,14 +30,10 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate. */ meshtastic_Config_DeviceConfig_Role_REPEATER = 4, /* Tracker device role - Position Mesh packets will be prioritized higher and sent more frequently by default. - When used in conjunction with power.is_power_saving = true, nodes will wake up, - send position, and then sleep for position.position_broadcast_secs seconds. */ + Position Mesh packets will be prioritized higher and sent more frequently by default. */ meshtastic_Config_DeviceConfig_Role_TRACKER = 5, /* Sensor device role - Telemetry Mesh packets will be prioritized higher and sent more frequently by default. - When used in conjunction with power.is_power_saving = true, nodes will wake up, - send environment telemetry, and then sleep for telemetry.environment_update_interval seconds. */ + Telemetry Mesh packets will be prioritized higher and sent more frequently by default. */ meshtastic_Config_DeviceConfig_Role_SENSOR = 6 } meshtastic_Config_DeviceConfig_Role; diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 2d6269888d..0a324e1074 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -65,8 +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; + /* Last byte of the node number of the node to use as a next hop in order to reach this node. */ + uint8_t next_hop; } meshtastic_NodeInfoLite; /* The on-disk saved channels */ @@ -317,8 +317,8 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg; /* Maximum encoded size of messages (where known) */ #define meshtastic_ChannelFile_size 638 -#define meshtastic_DeviceState_size 17490 -#define meshtastic_NodeInfoLite_size 157 +#define meshtastic_DeviceState_size 17193 +#define meshtastic_NodeInfoLite_size 154 #define meshtastic_NodeRemoteHardwarePin_size 29 #define meshtastic_OEMStore_size 3220 #define meshtastic_PositionLite_size 28 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 110c2217d5..1cab380855 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -563,12 +563,13 @@ 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; + /* Last byte of the node number of the node that should be used as the next hop in routing. */ + uint8_t next_hop; + /* Last byte of the node number of the node that will relay/relayed this packet. */ + uint8_t relay_node; + /* The hop limit setting of the original transmitter. + Useful to determine the amount of hops a packet traveled upon reception, which is this value minus the `hop_limit` with which it arrived. */ + uint32_t original_hop_limit; } meshtastic_MeshPacket; /* The bluetooth to device link: @@ -864,7 +865,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, 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, 0, 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} @@ -882,7 +883,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, 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, 0, 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} @@ -961,7 +962,8 @@ extern "C" { #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_MeshPacket_relay_node_tag 15 +#define meshtastic_MeshPacket_original_hop_limit_tag 16 #define meshtastic_NodeInfo_num_tag 1 #define meshtastic_NodeInfo_user_tag 2 #define meshtastic_NodeInfo_position_tag 3 @@ -1118,7 +1120,8 @@ 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, UINT32, next_hop, 14) \ -X(a, STATIC, SINGULAR, UINT32, current_relayer, 15) +X(a, STATIC, SINGULAR, UINT32, relay_node, 15) \ +X(a, STATIC, SINGULAR, UINT32, original_hop_limit, 16) #define meshtastic_MeshPacket_CALLBACK NULL #define meshtastic_MeshPacket_DEFAULT NULL #define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data @@ -1283,7 +1286,7 @@ 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 333 +#define meshtastic_MeshPacket_size 334 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 18 #define meshtastic_NeighborInfo_size 268 diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index c94349d47c..d354b7a42a 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -69,8 +69,7 @@ typedef enum _meshtastic_PortNum { NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate. This marker comes from the 'moduleConfig.audio.bitrate' enum minus one. */ meshtastic_PortNum_AUDIO_APP = 9, - /* Same as Text Message but originating from Detection Sensor Module. - NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 */ + /* Same as Text Message but originating from Detection Sensor Module. */ meshtastic_PortNum_DETECTION_SENSOR_APP = 10, /* Provides a 'ping' service that replies to any packet it receives. Also serves as a small example module. @@ -91,8 +90,7 @@ typedef enum _meshtastic_PortNum { ENCODING: Protobuf */ meshtastic_PortNum_STORE_FORWARD_APP = 65, /* Optional port for messages for the range test module. - ENCODING: ASCII Plaintext - NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 */ + ENCODING: ASCII Plaintext */ meshtastic_PortNum_RANGE_TEST_APP = 66, /* Provides a format to send and receive telemetry data from the Meshtastic network. Maintained by Charles Crossan (crossan007) : crossan007@gmail.com diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 09e7dd5cb3..6c1d2e9f50 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -161,7 +161,7 @@ size_t NeighborInfoModule::cleanUpNeighbors() // 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) { + if (node->next_hop == (uint8_t)(neighbors[index].node_id & 0xFF)) { node->next_hop = 0; } } @@ -251,7 +251,7 @@ void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np) 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 + currentNode->next_hop = (uint8_t)(np->node_id & 0xFF); // 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 @@ -259,7 +259,7 @@ void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np) 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; + neighborOfCurrentNode->next_hop = (uint8_t)(currentNode->num & 0xFF); } } else if (currentNode) { // Sender is not a neighbor // Find common neighbors and use the most recent as next hop to this node @@ -270,7 +270,7 @@ void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np) 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; + currentNode->next_hop = (uint8_t)(neighborOfCurrentNode->num & 0xFF); maxLastHeard = neighborOfCurrentNode->last_heard; LOG_DEBUG("More recent node found, so update next_hop of %x to %x\n", currentNode->num, neighborOfCurrentNode->num); @@ -369,4 +369,4 @@ bool NeighborInfoModule::saveProtoForModule() okay &= nodeDB.saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState); return okay; -} +} \ No newline at end of file From 9b1dd75549c3d1cff9dc14316c7ee78594322210 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 14 Oct 2023 17:17:12 +0200 Subject: [PATCH 03/32] Short-circuit to FloodingRouter for broadcasts --- src/mesh/NextHopRouter.cpp | 7 ++----- src/mesh/ReliableRouter.cpp | 35 +++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 68f4ec6209..40f34d1fd2 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -66,14 +66,11 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast tosend->hop_limit--; // bump down the hop count NextHopRouter::send(tosend); - } else if (p->next_hop == 0) { + } else if (p->next_hop == NO_NEXT_HOP_PREFERENCE) { // 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: Smarter way of handling broadcasts - FloodingRouter::sniffReceived(p, c); - } + } // else don't relay } } else { LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n"); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 70af96d8bd..fa85b1af4d 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -33,7 +33,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) } } - return config.lora.next_hop_routing ? NextHopRouter::send(p) : FloodingRouter::send(p); + return (config.lora.next_hop_routing && p->to != NODENUM_BROADCAST) ? NextHopRouter::send(p) : FloodingRouter::send(p); } bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) @@ -132,8 +132,9 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas } } - // handle the packet as normal - config.lora.next_hop_routing ? NextHopRouter::sniffReceived(p, c) : FloodingRouter::sniffReceived(p, c); + // For DMs, we use the NextHopRouter, whereas for broadcasts, we use the FloodingRouter + config.lora.next_hop_routing && (p->to != NODENUM_BROADCAST) ? NextHopRouter::sniffReceived(p, c) + : FloodingRouter::sniffReceived(p, c); } #define NUM_RETRANSMISSIONS 3 @@ -222,22 +223,24 @@ 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 = NO_NEXT_HOP_PREFERENCE; - // 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 0x%x\n", p.packet->to); - sentTo->next_hop = NO_NEXT_HOP_PREFERENCE; + if (config.lora.next_hop_routing && p.packet->to != NODENUM_BROADCAST) { + if (p.numRetransmissions == 1) { + // Last retransmission, reset next_hop (fallback to FloodingRouter) + p.packet->next_hop = NO_NEXT_HOP_PREFERENCE; + // 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 0x%x\n", p.packet->to); + sentTo->next_hop = NO_NEXT_HOP_PREFERENCE; + } } + NextHopRouter::send(packetPool.allocCopy(*p.packet)); + } else { + // 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)); } - // Note: we call the superclass version because we don't want to have our version of send() add a new - // retransmission record - config.lora.next_hop_routing ? NextHopRouter::send(packetPool.allocCopy(*p.packet)) - : FloodingRouter::send(packetPool.allocCopy(*p.packet)); - // Queue again --p.numRetransmissions; setNextTx(&p); From 27a492adf866f52c54a5595e6109cc58af562312 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 14 Oct 2023 17:18:05 +0200 Subject: [PATCH 04/32] If packet traveled 1 hop, set `relay_node` as `next_hop` for the original transmitter --- src/mesh/NodeDB.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 198abdd7ca..1eb01e9ea5 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -795,6 +795,9 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) // If this packet didn't travel any hops, then it was sent directly to us, so we know what to use as next hop to this node if (mp.original_hop_limit == mp.hop_limit) { info->next_hop = (uint8_t)(mp.from & 0xFF); + } else if (mp.relay_node && (mp.original_hop_limit - mp.hop_limit == 1)) { + // This packet traveled one hop, so we can use the relay_node as next_hop + info->next_hop = (uint8_t)(mp.relay_node & 0xFF); } } } From ef2c6eed054ac45caab1a1d3bd3082a8ad5fb9b2 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Mon, 27 Nov 2023 20:36:48 +0100 Subject: [PATCH 05/32] Set last byte to 0xFF if it ended at 0x00 As per an idea of @S5NC --- src/mesh/NextHopRouter.cpp | 4 ++-- src/mesh/NodeDB.cpp | 4 ++-- src/mesh/NodeDB.h | 3 +++ src/mesh/Router.cpp | 4 ++-- src/modules/NeighborInfoModule.cpp | 8 ++++---- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 40f34d1fd2..64d87f12fc 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -19,7 +19,7 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { if (wasSeenRecently(p)) { // Note: this will also add a recent packet record - if (p->next_hop == (uint8_t)(getNodeNum() & 0xFF)) { + if (p->next_hop == nodeDB.getLastByteOfNodeNum(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"); @@ -51,7 +51,7 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { if ((p->to != getNodeNum()) && (getFrom(p) != getNodeNum())) { - if (p->next_hop == (uint8_t)(getNodeNum() & 0xFF)) { + if (p->next_hop == nodeDB.getLastByteOfNodeNum(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->relay_node); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 4fc2c77239..8468cf7f0f 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -824,10 +824,10 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) // If this packet didn't travel any hops, then it was sent directly to us, so we know what to use as next hop to this node if (mp.original_hop_limit == mp.hop_limit) { - info->next_hop = (uint8_t)(mp.from & 0xFF); + info->next_hop = getLastByteOfNodeNum(mp.from); } else if (mp.relay_node && (mp.original_hop_limit - mp.hop_limit == 1)) { // This packet traveled one hop, so we can use the relay_node as next_hop - info->next_hop = (uint8_t)(mp.relay_node & 0xFF); + info->next_hop = getLastByteOfNodeNum(mp.relay_node); } } } diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index d706552d77..795104280b 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -91,6 +91,9 @@ class NodeDB /// @return our node number NodeNum getNodeNum() { return myNodeInfo.my_node_num; } + // @return last byte of a NodeNum, 0xFF if it ended at 0x00 + uint8_t getLastByteOfNodeNum(NodeNum num) { return (uint8_t)((num & 0xFF) ? (num & 0xFF) : 0xFF); } + /// if returns false, that means our node should send a DenyNodeNum response. If true, we think the number is okay for use // bool handleWantNodeNum(NodeNum n); diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 58394b8332..c33078c87b 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -241,10 +241,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) p->from = getFrom(p); // If we are the original transmitter, set the original hop limit - if (p->from == nodeDB.getNodeNum()) + if (p->from == getNodeNum()) p->original_hop_limit = config.lora.hop_limit ? config.lora.hop_limit : HOP_RELIABLE; - p->relay_node = (uint8_t)(getNodeNum() & 0xFF); // set the current relayer to us + p->relay_node = nodeDB.getLastByteOfNodeNum(getNodeNum()); // set the 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) diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 6c1d2e9f50..6060e384ec 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -161,7 +161,7 @@ size_t NeighborInfoModule::cleanUpNeighbors() // 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 == (uint8_t)(neighbors[index].node_id & 0xFF)) { + if (node->next_hop == nodeDB.getLastByteOfNodeNum(neighbors[index].node_id)) { node->next_hop = 0; } } @@ -251,7 +251,7 @@ void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np) 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 = (uint8_t)(np->node_id & 0xFF); // Set the next hop to the sender of this packet + currentNode->next_hop = nodeDB.getLastByteOfNodeNum(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 @@ -259,7 +259,7 @@ void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np) 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 = (uint8_t)(currentNode->num & 0xFF); + neighborOfCurrentNode->next_hop = nodeDB.getLastByteOfNodeNum(currentNode->num); } } else if (currentNode) { // Sender is not a neighbor // Find common neighbors and use the most recent as next hop to this node @@ -270,7 +270,7 @@ void NeighborInfoModule::updateNextHops(meshtastic_NeighborInfo *np) if (neighborOfCurrentNode && isANeighbor(neighborOfCurrentNode->num)) { // This neighbor was heard more recently than the current next hop if (neighborOfCurrentNode->last_heard > maxLastHeard) { - currentNode->next_hop = (uint8_t)(neighborOfCurrentNode->num & 0xFF); + currentNode->next_hop = nodeDB.getLastByteOfNodeNum(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); From 3ba9ecbbfe3890632615f86d10da0c0518b4ef9d Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 28 Nov 2023 19:53:40 +0100 Subject: [PATCH 06/32] Also update next-hop based on received DM for us --- src/mesh/NextHopRouter.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 64d87f12fc..61a5d9dfd3 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -33,25 +33,26 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { + NodeNum ourNodeNum = getNodeNum(); 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 the relay node, 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 (isAck || (p->to == ourNodeNum)) { + // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is + // not 0 or ourselves (means implicit ACK or someone is relaying our ACK) + if (p->from != 0 && p->from != ourNodeNum) { if (p->relay_node) { - meshtastic_NodeInfoLite *sentTo = nodeDB.getMeshNode(p->from); - if (sentTo) { - LOG_DEBUG("Update next hop of 0x%x to 0x%x based on received ACK.\n", p->from, p->relay_node); - sentTo->next_hop = p->relay_node; + meshtastic_NodeInfoLite *origTx = nodeDB.getMeshNode(p->from); + if (origTx) { + LOG_DEBUG("Update next hop of 0x%x to 0x%x based on received DM or ACK.\n", p->from, p->relay_node); + origTx->next_hop = p->relay_node; } } } } if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { - if ((p->to != getNodeNum()) && (getFrom(p) != getNodeNum())) { - if (p->next_hop == nodeDB.getLastByteOfNodeNum(getNodeNum())) { + if ((p->to != ourNodeNum) && (getFrom(p) != ourNodeNum)) { + if (p->next_hop == nodeDB.getLastByteOfNodeNum(ourNodeNum)) { 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->relay_node); From 913268b13295db38aa027eaeb401e392554549b5 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 9 Aug 2024 08:53:04 +0200 Subject: [PATCH 07/32] temp --- src/mesh/NextHopRouter.h | 89 +++++++++++++++++++++++++++++++++++++++ src/mesh/ReliableRouter.h | 88 -------------------------------------- 2 files changed, 89 insertions(+), 88 deletions(-) diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 57b5e68f0c..47cfbfe9b3 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -2,6 +2,51 @@ #include "FloodingRouter.h" +/** + * An identifier for a globally unique message - a pair of the sending nodenum and the packet id assigned + * to that message + */ +struct GlobalPacketId { + NodeNum node; + PacketId id; + + bool operator==(const GlobalPacketId &p) const { return node == p.node && id == p.id; } + + explicit GlobalPacketId(const meshtastic_MeshPacket *p) + { + node = getFrom(p); + id = p->id; + } + + GlobalPacketId(NodeNum _from, PacketId _id) + { + node = _from; + id = _id; + } +}; + +/** + * A packet queued for retransmission + */ +struct PendingPacket { + meshtastic_MeshPacket *packet; + + /** The next time we should try to retransmit this packet */ + uint32_t nextTxMsec = 0; + + /** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */ + uint8_t numRetransmissions = 0; + + PendingPacket() {} + explicit PendingPacket(meshtastic_MeshPacket *p); +}; + +class GlobalPacketIdHashFunction +{ + public: + size_t operator()(const GlobalPacketId &p) const { return (std::hash()(p.node)) ^ (std::hash()(p.id)); } +}; + /* Router which only relays if it is the next hop for a packet. The next hop is set by the relay node of a packet, which bases this on information from either the NeighborInfoModule, or a @@ -26,7 +71,23 @@ class NextHopRouter : public FloodingRouter */ virtual ErrorCode send(meshtastic_MeshPacket *p) override; + /** Do our retransmission handling */ + virtual int32_t runOnce() override + { + // Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation + auto d = doRetransmissions(); + + int32_t r = FloodingRouter::runOnce(); + + return min(d, r); + } + protected: + /** + * Pending retransmissions + */ + std::unordered_map pending; + /** * Should this incoming filter be dropped? * @@ -42,10 +103,38 @@ class NextHopRouter : public FloodingRouter constexpr static uint8_t NO_NEXT_HOP_PREFERENCE = 0; + /** + * Try to find the pending packet record for this ID (or NULL if not found) + */ + PendingPacket *findPendingPacket(NodeNum from, PacketId id) { return findPendingPacket(GlobalPacketId(from, id)); } + PendingPacket *findPendingPacket(GlobalPacketId p); + + /** + * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. + */ + PendingPacket *startRetransmission(meshtastic_MeshPacket *p); + private: /** * Get the next hop for a destination, given the relay node * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) */ uint8_t getNextHop(NodeNum to, uint8_t relay_node); + + /** + * Stop any retransmissions we are doing of the specified node/packet ID pair + * + * @return true if we found and removed a transmission with this ID + */ + bool stopRetransmission(NodeNum from, PacketId id); + bool stopRetransmission(GlobalPacketId p); + + /** + * Do any retransmissions that are scheduled (FIXME - for the time being called from loop) + * + * @return the number of msecs until our next retransmission or MAXINT if none scheduled + */ + int32_t doRetransmissions(); + + void setNextTx(PendingPacket *pending); }; \ No newline at end of file diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index c5ceff73bd..ed278349a3 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -3,59 +3,11 @@ #include "NextHopRouter.h" #include -/** - * An identifier for a globalally unique message - a pair of the sending nodenum and the packet id assigned - * to that message - */ -struct GlobalPacketId { - NodeNum node; - PacketId id; - - bool operator==(const GlobalPacketId &p) const { return node == p.node && id == p.id; } - - explicit GlobalPacketId(const meshtastic_MeshPacket *p) - { - node = getFrom(p); - id = p->id; - } - - GlobalPacketId(NodeNum _from, PacketId _id) - { - node = _from; - id = _id; - } -}; - -/** - * A packet queued for retransmission - */ -struct PendingPacket { - meshtastic_MeshPacket *packet; - - /** The next time we should try to retransmit this packet */ - uint32_t nextTxMsec = 0; - - /** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */ - uint8_t numRetransmissions = 0; - - PendingPacket() {} - explicit PendingPacket(meshtastic_MeshPacket *p); -}; - -class GlobalPacketIdHashFunction -{ - public: - size_t operator()(const GlobalPacketId &p) const { return (std::hash()(p.node)) ^ (std::hash()(p.id)); } -}; - /** * This is a mixin that extends Router with the ability to do (one hop only) reliable message sends. */ class ReliableRouter : public NextHopRouter { - private: - std::unordered_map pending; - public: /** * Constructor @@ -70,54 +22,14 @@ class ReliableRouter : public NextHopRouter */ virtual ErrorCode send(meshtastic_MeshPacket *p) override; - /** Do our retransmission handling */ - virtual int32_t runOnce() override - { - // Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation - auto d = doRetransmissions(); - - int32_t r = FloodingRouter::runOnce(); - - return min(d, r); - } - protected: /** * Look for acks/naks or someone retransmitting us */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; - /** - * Try to find the pending packet record for this ID (or NULL if not found) - */ - PendingPacket *findPendingPacket(NodeNum from, PacketId id) { return findPendingPacket(GlobalPacketId(from, id)); } - PendingPacket *findPendingPacket(GlobalPacketId p); - /** * We hook this method so we can see packets before FloodingRouter says they should be discarded */ virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override; - - /** - * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. - */ - PendingPacket *startRetransmission(meshtastic_MeshPacket *p); - - private: - /** - * Stop any retransmissions we are doing of the specified node/packet ID pair - * - * @return true if we found and removed a transmission with this ID - */ - bool stopRetransmission(NodeNum from, PacketId id); - bool stopRetransmission(GlobalPacketId p); - - /** - * Do any retransmissions that are scheduled (FIXME - for the time being called from loop) - * - * @return the number of msecs until our next retransmission or MAXINT if none scheduled - */ - int32_t doRetransmissions(); - - void setNextTx(PendingPacket *pending); }; \ No newline at end of file From 2e303a33be702ddd11d4d89f85e4d210f7d06c59 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 10 Aug 2024 20:46:27 +0200 Subject: [PATCH 08/32] Add 1 retransmission for intermediate hops when using NextHopRouter --- src/main.cpp | 2 +- src/mesh/FloodingRouter.cpp | 8 +- src/mesh/NextHopRouter.cpp | 176 ++++++++++++++++++++++++++++++++---- src/mesh/NextHopRouter.h | 21 +++-- src/mesh/NodeDB.cpp | 5 - src/mesh/RadioInterface.cpp | 6 +- src/mesh/ReliableRouter.cpp | 141 +---------------------------- src/mesh/ReliableRouter.h | 3 +- 8 files changed, 181 insertions(+), 181 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6e337bb8ce..82acb6e1d0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -605,7 +605,7 @@ void setup() // If we're taking on the repeater role, use flood router and turn off 3V3_S rail because peripherals are not needed if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { - router = new FloodingRouter(); + router = new NextHopRouter(); #ifdef PIN_3V3_EN digitalWrite(PIN_3V3_EN, LOW); #endif diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 0a50e95564..bac84203f9 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -35,12 +35,6 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { - bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); - if (isAckorReply && p->to != getNodeNum() && p->to != NODENUM_BROADCAST) { - // do not flood direct message that is ACKed or replied to - LOG_DEBUG("Receiving an ACK or reply not for me, but don't need to rebroadcast this direct message anymore.\n"); - Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM - } if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) { if (p->id != 0) { if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { @@ -68,4 +62,4 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas } // handle the packet as normal Router::sniffReceived(p, c); -} +} \ No newline at end of file diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 8b29217b67..5c7b9bd493 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -2,6 +2,12 @@ NextHopRouter::NextHopRouter() {} +PendingPacket::PendingPacket(meshtastic_MeshPacket *p, uint8_t numRetransmissions) +{ + packet = p; + this->numRetransmissions = numRetransmissions - 1; // We subtract one, because we assume the user just did the first send +} + /** * Send a packet */ @@ -13,6 +19,9 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) p->next_hop = getNextHop(p->to, p->relay_node); // set the next hop LOG_DEBUG("Setting next hop for packet with dest %x to %x\n", p->to, p->next_hop); + if (p->next_hop != NO_NEXT_HOP_PREFERENCE && (p->want_ack || (p->to != p->next_hop && p->hop_limit > 0))) + startRetransmission(packetPool.allocCopy(*p)); // start retransmission for relayed packet + return Router::send(p); } @@ -23,6 +32,7 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) 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"); + stopRetransmission(p->from, p->id); Router::cancelSending(p->from, p->id); } return true; @@ -34,34 +44,34 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { NodeNum ourNodeNum = getNodeNum(); - bool isAck = - ((c && c->error_reason == meshtastic_Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK - if (isAck || (p->to == ourNodeNum)) { + bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); + if (isAckorReply) { // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is - // not 0 or ourselves (means implicit ACK or someone is relaying our ACK) - if (p->from != 0 && p->from != ourNodeNum) { - if (p->relay_node) { + // not 0 (means implicit ACK) + if (p->to == ourNodeNum && p->from != 0) { + if (p->hop_start && p->relay_node) { // Only if hopStart is set, relay_node is valid (both introduced in v2.3) meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); if (origTx) { - LOG_DEBUG("Update next hop of 0x%x to 0x%x based on received DM or ACK.\n", p->from, p->relay_node); + LOG_DEBUG("Update next hop of 0x%x to 0x%x based on received ACK or reply.\n", p->from, p->relay_node); origTx->next_hop = p->relay_node; } } } + + LOG_DEBUG("Receiving an ACK or reply, don't need to relay this packet anymore.\n"); + Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM + stopRetransmission(p->from, p->decoded.request_id); } if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { if ((p->to != ourNodeNum) && (getFrom(p) != ourNodeNum)) { - if (p->next_hop == nodeDB->getLastByteOfNodeNum(ourNodeNum)) { + if (p->hop_start == 0 || p->next_hop == NO_NEXT_HOP_PREFERENCE || + p->next_hop == nodeDB->getLastByteOfNodeNum(ourNodeNum)) { 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->relay_node); + LOG_INFO("Relaying received message coming from %x\n", p->relay_node); tosend->hop_limit--; // bump down the hop count NextHopRouter::send(tosend); - } else if (p->next_hop == NO_NEXT_HOP_PREFERENCE) { - // No preference for next hop, use FloodingRouter - LOG_DEBUG("No preference for next hop, using FloodingRouter\n"); - FloodingRouter::sniffReceived(p, c); } // else don't relay } } else { @@ -80,14 +90,144 @@ uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node) meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(to); if (node) { // We are careful not to return the relay node as the next hop - if (node->next_hop != relay_node) { + if (node->next_hop && node->next_hop != relay_node) { LOG_DEBUG("Next hop for 0x%x is 0x%x\n", to, node->next_hop); return node->next_hop; } else { - LOG_WARN("Next hop for 0x%x is 0x%x, same as relayer; setting as no preference\n", to, node->next_hop); - return NO_NEXT_HOP_PREFERENCE; + if (node->next_hop) + LOG_WARN("Next hop for 0x%x is 0x%x, same as relayer; setting as no preference\n", to, node->next_hop); + } + } + return NO_NEXT_HOP_PREFERENCE; +} + +PendingPacket *NextHopRouter::findPendingPacket(GlobalPacketId key) +{ + auto old = pending.find(key); // If we have an old record, someone messed up because id got reused + if (old != pending.end()) { + return &old->second; + } else + return NULL; +} +/** + * Stop any retransmissions we are doing of the specified node/packet ID pair + */ +bool NextHopRouter::stopRetransmission(NodeNum from, PacketId id) +{ + auto key = GlobalPacketId(from, id); + return stopRetransmission(key); +} + +bool NextHopRouter::stopRetransmission(GlobalPacketId key) +{ + auto old = findPendingPacket(key); + if (old) { + auto p = old->packet; + /* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue + to avoid canceling a transmission if it was ACKed super fast via MQTT */ + if (old->numRetransmissions < NUM_RETRANSMISSIONS - 1) { + // remove the 'original' (identified by originator and packet->id) from the txqueue and free it + cancelSending(getFrom(p), p->id); + // now free the pooled copy for retransmission too + packetPool.release(p); + } + auto numErased = pending.erase(key); + assert(numErased == 1); + return true; + } else + return false; +} + +/** + * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. + */ +PendingPacket *NextHopRouter::startRetransmission(meshtastic_MeshPacket *p) +{ + auto id = GlobalPacketId(p); + auto rec = PendingPacket(p, this->NUM_RETRANSMISSIONS); + + stopRetransmission(getFrom(p), p->id); + + setNextTx(&rec); + pending[id] = rec; + + return &pending[id]; +} + +/** + * Do any retransmissions that are scheduled (FIXME - for the time being called from loop) + */ +int32_t NextHopRouter::doRetransmissions() +{ + uint32_t now = millis(); + int32_t d = INT32_MAX; + + // FIXME, we should use a better datastructure rather than walking through this map. + // for(auto el: pending) { + for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) { + ++nextIt; // we use this odd pattern because we might be deleting it... + auto &p = it->second; + + bool stillValid = true; // assume we'll keep this record around + + // FIXME, handle 51 day rolloever here!!! + if (p.nextTxMsec <= now) { + if (p.numRetransmissions == 0) { + if (p.packet->from == getNodeNum()) { + LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, + p.packet->id); + sendAckNak(meshtastic_Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); + } + // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived + stopRetransmission(it->first); + stillValid = false; // just deleted it + } else { + LOG_DEBUG("Sending 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.packet->to != NODENUM_BROADCAST) { + if (p.numRetransmissions == 1) { + // Last retransmission, reset next_hop (fallback to FloodingRouter) + p.packet->next_hop = NO_NEXT_HOP_PREFERENCE; + // 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 0x%x\n", p.packet->to); + sentTo->next_hop = NO_NEXT_HOP_PREFERENCE; + } + FloodingRouter::send(packetPool.allocCopy(*p.packet)); + } else { + NextHopRouter::send(packetPool.allocCopy(*p.packet)); + } + } else { + // 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)); + } + + // Queue again + --p.numRetransmissions; + setNextTx(&p); + } + } + + if (stillValid) { + // Update our desired sleep delay + int32_t t = p.nextTxMsec - now; + + d = min(t, d); } - } else { - return NO_NEXT_HOP_PREFERENCE; } + + return d; +} + +void NextHopRouter::setNextTx(PendingPacket *pending) +{ + assert(iface); + auto d = iface->getRetransmissionMsec(pending->packet); + pending->nextTxMsec = millis() + d; + LOG_DEBUG("Setting next retransmission in %u msecs: ", d); + printPacket("", pending->packet); + setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time } \ No newline at end of file diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 47cfbfe9b3..731ed8b8b6 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -1,6 +1,7 @@ #pragma once #include "FloodingRouter.h" +#include /** * An identifier for a globally unique message - a pair of the sending nodenum and the packet id assigned @@ -34,11 +35,11 @@ struct PendingPacket { /** The next time we should try to retransmit this packet */ uint32_t nextTxMsec = 0; - /** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */ + /** Starts at NUM_RETRANSMISSIONS -1 and counts down. Once zero it will be removed from the list */ uint8_t numRetransmissions = 0; PendingPacket() {} - explicit PendingPacket(meshtastic_MeshPacket *p); + explicit PendingPacket(meshtastic_MeshPacket *p, uint8_t numRetransmissions); }; class GlobalPacketIdHashFunction @@ -82,6 +83,8 @@ class NextHopRouter : public FloodingRouter return min(d, r); } + constexpr static uint8_t NUM_RETRANSMISSIONS = 2; + protected: /** * Pending retransmissions @@ -114,13 +117,6 @@ class NextHopRouter : public FloodingRouter */ PendingPacket *startRetransmission(meshtastic_MeshPacket *p); - private: - /** - * Get the next hop for a destination, given the relay node - * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) - */ - uint8_t getNextHop(NodeNum to, uint8_t relay_node); - /** * Stop any retransmissions we are doing of the specified node/packet ID pair * @@ -137,4 +133,11 @@ class NextHopRouter : public FloodingRouter int32_t doRetransmissions(); void setNextTx(PendingPacket *pending); + + private: + /** + * Get the next hop for a destination, given the relay node + * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) + */ + uint8_t getNextHop(NodeNum to, uint8_t relay_node); }; \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index efc2733d67..cb333edf9d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1095,11 +1095,6 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp) // If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) { info->hops_away = mp.hop_start - mp.hop_limit; - if (info->hops_away == 0) { - info->next_hop = getLastByteOfNodeNum(mp.from); - } else if (info->hops_away == 1) { - info->next_hop = getLastByteOfNodeNum(mp.relay_node); - } } } } diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 5ffd553285..1909d92e6d 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -306,6 +306,10 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p) out += " encrypted"; } + if (p->next_hop != 0) + out += DEBUG_PORT.mt_sprintf(" nextHop=0x%x", p->next_hop); + if (p->relay_node != 0) + out += DEBUG_PORT.mt_sprintf(" relay=0x%x", p->relay_node); if (p->rx_time != 0) out += DEBUG_PORT.mt_sprintf(" rxtime=%u", p->rx_time); if (p->rx_snr != 0.0) @@ -617,4 +621,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) sendingPacket = p; return p->encrypted.size + sizeof(PacketHeader); -} +} \ No newline at end of file diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index d26deaead3..a4bc9b431a 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -85,7 +85,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) Router::send(tosend); } - return config.lora.next_hop_routing ? NextHopRouter::shouldFilterReceived(p) : FloodingRouter::shouldFilterReceived(p); + return p->to == NODENUM_BROADCAST ? FloodingRouter::shouldFilterReceived(p) : NextHopRouter::shouldFilterReceived(p); } /** @@ -146,142 +146,5 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas } } - // For DMs, we use the NextHopRouter, whereas for broadcasts, we use the FloodingRouter - config.lora.next_hop_routing && (p->to != NODENUM_BROADCAST) ? NextHopRouter::sniffReceived(p, c) - : FloodingRouter::sniffReceived(p, c); -} - -#define NUM_RETRANSMISSIONS 3 - -PendingPacket::PendingPacket(meshtastic_MeshPacket *p) -{ - packet = p; - numRetransmissions = NUM_RETRANSMISSIONS - 1; // We subtract one, because we assume the user just did the first send -} - -PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key) -{ - auto old = pending.find(key); // If we have an old record, someone messed up because id got reused - if (old != pending.end()) { - return &old->second; - } else - return NULL; -} -/** - * Stop any retransmissions we are doing of the specified node/packet ID pair - */ -bool ReliableRouter::stopRetransmission(NodeNum from, PacketId id) -{ - auto key = GlobalPacketId(from, id); - return stopRetransmission(key); -} - -bool ReliableRouter::stopRetransmission(GlobalPacketId key) -{ - auto old = findPendingPacket(key); - if (old) { - auto p = old->packet; - /* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue - to avoid canceling a transmission if it was ACKed super fast via MQTT */ - if (old->numRetransmissions < NUM_RETRANSMISSIONS - 1) { - // remove the 'original' (identified by originator and packet->id) from the txqueue and free it - cancelSending(getFrom(p), p->id); - // now free the pooled copy for retransmission too - packetPool.release(p); - } - auto numErased = pending.erase(key); - assert(numErased == 1); - return true; - } else - return false; -} - -/** - * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. - */ -PendingPacket *ReliableRouter::startRetransmission(meshtastic_MeshPacket *p) -{ - auto id = GlobalPacketId(p); - auto rec = PendingPacket(p); - - stopRetransmission(getFrom(p), p->id); - - setNextTx(&rec); - pending[id] = rec; - - return &pending[id]; -} - -/** - * Do any retransmissions that are scheduled (FIXME - for the time being called from loop) - */ -int32_t ReliableRouter::doRetransmissions() -{ - uint32_t now = millis(); - int32_t d = INT32_MAX; - - // FIXME, we should use a better datastructure rather than walking through this map. - // for(auto el: pending) { - for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) { - ++nextIt; // we use this odd pattern because we might be deleting it... - auto &p = it->second; - - bool stillValid = true; // assume we'll keep this record around - - // FIXME, handle 51 day rolloever here!!! - if (p.nextTxMsec <= now) { - if (p.numRetransmissions == 0) { - LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, - p.packet->id); - sendAckNak(meshtastic_Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); - // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - stopRetransmission(it->first); - stillValid = false; // just deleted it - } else { - 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.packet->to != NODENUM_BROADCAST) { - if (p.numRetransmissions == 1) { - // Last retransmission, reset next_hop (fallback to FloodingRouter) - p.packet->next_hop = NO_NEXT_HOP_PREFERENCE; - // 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 0x%x\n", p.packet->to); - sentTo->next_hop = NO_NEXT_HOP_PREFERENCE; - } - } - NextHopRouter::send(packetPool.allocCopy(*p.packet)); - } else { - // 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)); - } - - // Queue again - --p.numRetransmissions; - setNextTx(&p); - } - } - - if (stillValid) { - // Update our desired sleep delay - int32_t t = p.nextTxMsec - now; - - d = min(t, d); - } - } - - return d; -} - -void ReliableRouter::setNextTx(PendingPacket *pending) -{ - assert(iface); - auto d = iface->getRetransmissionMsec(pending->packet); - pending->nextTxMsec = millis() + d; - LOG_DEBUG("Setting next retransmission in %u msecs: ", d); - printPacket("", pending->packet); - setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time + p->to == NODENUM_BROADCAST ? FloodingRouter::sniffReceived(p, c) : NextHopRouter::sniffReceived(p, c); } \ No newline at end of file diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index ed278349a3..b1ad99cd33 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -1,7 +1,6 @@ #pragma once #include "NextHopRouter.h" -#include /** * This is a mixin that extends Router with the ability to do (one hop only) reliable message sends. @@ -32,4 +31,6 @@ class ReliableRouter : public NextHopRouter * We hook this method so we can see packets before FloodingRouter says they should be discarded */ virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override; + + constexpr static uint8_t NUM_RETRANSMISSIONS = 3; }; \ No newline at end of file From 6fe42ed4c5536c7116feaa13578f7013d4d69de4 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 1 Nov 2024 09:16:51 +0100 Subject: [PATCH 09/32] Add next_hop and relayed_by in PacketHistory for setting next-hop and handle flooding fallback --- src/main.cpp | 6 +- src/mesh/FloodingRouter.cpp | 3 +- src/mesh/MeshService.cpp | 10 +-- src/mesh/MeshTypes.h | 3 + src/mesh/NextHopRouter.cpp | 23 +++--- src/mesh/NextHopRouter.h | 2 - src/mesh/PacketHistory.cpp | 31 +++++++- src/mesh/PacketHistory.h | 8 ++- src/mesh/RadioLibInterface.cpp | 5 +- src/mesh/ReliableRouter.cpp | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 13 ++-- src/mesh/generated/meshtastic/config.pb.cpp | 21 +----- src/mesh/generated/meshtastic/config.pb.h | 70 ++++++++----------- src/mesh/generated/meshtastic/deviceonly.pb.h | 7 +- src/mesh/generated/meshtastic/localonly.pb.h | 4 +- src/mesh/generated/meshtastic/mesh.pb.h | 51 +++++--------- src/mesh/generated/meshtastic/telemetry.pb.h | 5 +- src/modules/AdminModule.cpp | 4 +- src/modules/Modules.cpp | 14 +--- src/modules/NodeInfoModule.cpp | 2 +- src/modules/Telemetry/DeviceTelemetry.h | 5 +- 21 files changed, 130 insertions(+), 159 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 82acb6e1d0..46b5bea1f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -727,11 +727,7 @@ void setup() audioThread = new AudioThread(); #endif - config.lora.next_hop_routing = true; // FIXME - remove this before merging - LOG_INFO("USING NEXT-HOP ROUTING\n"); - - service = new MeshService(); - service->init(); + service.init(); // Now that the mesh service is created, create any modules setupModules(); diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index bac84203f9..da4c6f9691 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -13,7 +13,8 @@ FloodingRouter::FloodingRouter() {} ErrorCode FloodingRouter::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->relay_node = nodeDB->getLastByteOfNodeNum(getNodeNum()); // First set the relayer to us + wasSeenRecently(p); // FIXME, move this to a sniffSent method return Router::send(p); } diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index ac97d51a71..c833c0dec2 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -85,12 +85,8 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp) "request for its NodeInfo.\n"); } else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user && nodeInfoModule) { - LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel); - if (airTime->isTxAllowedChannelUtil(true)) { - nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); - } else { - LOG_DEBUG("Skip sending NodeInfo due to > 25 percent channel util.\n"); - } + // LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel); + // nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); } printPacket("Forwarding to phone", mp); @@ -407,4 +403,4 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus) bool MeshService::isToPhoneQueueEmpty() { return toPhoneQueue.isEmpty(); -} +} \ No newline at end of file diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 90cfd5897c..e8187b4c1a 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -39,6 +39,9 @@ enum RxSource { /// We normally just use max 3 hops for sending reliable messages #define HOP_RELIABLE 3 +// For old firmware or when falling back to flooding, there is no next-hop preference +#define NO_NEXT_HOP_PREFERENCE 0 + typedef int ErrorCode; /// Alloc and free packets to our global, ISR safe pool diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 5c7b9bd493..08dcdf3930 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -14,7 +14,8 @@ PendingPacket::PendingPacket(meshtastic_MeshPacket *p, uint8_t numRetransmission 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->relay_node = nodeDB->getLastByteOfNodeNum(getNodeNum()); // First set the relayer to us + wasSeenRecently(p); // FIXME, move this to a sniffSent method p->next_hop = getNextHop(p->to, p->relay_node); // set the next hop LOG_DEBUG("Setting next hop for packet with dest %x to %x\n", p->to, p->next_hop); @@ -44,14 +45,21 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { NodeNum ourNodeNum = getNodeNum(); + // TODO DMs are now usually not decoded! bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); if (isAckorReply) { // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is - // not 0 (means implicit ACK) + // not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the destination if (p->to == ourNodeNum && p->from != 0) { - if (p->hop_start && p->relay_node) { // Only if hopStart is set, relay_node is valid (both introduced in v2.3) + if (p->relay_node) { + // Check who was the original relayer of this packet + uint8_t original_relayer = PacketHistory::getRelayerFromHistory(p->decoded.request_id, p->to); + uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(ourNodeNum); meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); - if (origTx) { + // Either original relayer and relayer of ACK are the same, or we were the relayer and the ACK came directly from + // the destination + if (origTx && original_relayer == p->relay_node || + original_relayer == ourRelayID && p->relay_node == nodeDB->getLastByteOfNodeNum(p->from)) { LOG_DEBUG("Update next hop of 0x%x to 0x%x based on received ACK or reply.\n", p->from, p->relay_node); origTx->next_hop = p->relay_node; } @@ -65,8 +73,7 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { if ((p->to != ourNodeNum) && (getFrom(p) != ourNodeNum)) { - if (p->hop_start == 0 || p->next_hop == NO_NEXT_HOP_PREFERENCE || - p->next_hop == nodeDB->getLastByteOfNodeNum(ourNodeNum)) { + if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(ourNodeNum)) { meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it LOG_INFO("Relaying received message coming from %x\n", p->relay_node); @@ -185,14 +192,14 @@ int32_t NextHopRouter::doRetransmissions() LOG_DEBUG("Sending 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.packet->to != NODENUM_BROADCAST) { + if (p.packet->to != NODENUM_BROADCAST) { if (p.numRetransmissions == 1) { // Last retransmission, reset next_hop (fallback to FloodingRouter) p.packet->next_hop = NO_NEXT_HOP_PREFERENCE; // 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 0x%x\n", p.packet->to); + LOG_WARN("Resetting next hop for packet with dest 0x%x\n", p.packet->to); sentTo->next_hop = NO_NEXT_HOP_PREFERENCE; } FloodingRouter::send(packetPool.allocCopy(*p.packet)); diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 731ed8b8b6..07185f0889 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -104,8 +104,6 @@ class NextHopRouter : public FloodingRouter */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; - constexpr static uint8_t NO_NEXT_HOP_PREFERENCE = 0; - /** * Try to find the pending packet record for this ID (or NULL if not found) */ diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 26a73a3fe8..51dc8889e2 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -28,6 +28,8 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd r.id = p->id; r.sender = getFrom(p); r.rxTimeMsec = now; + r.next_hop = p->next_hop; + r.relayed_by = p->relay_node; auto found = recentPackets.find(r); bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently @@ -38,13 +40,22 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd seenRecently = false; } + if (seenRecently) { + // If it was seen with a next-hop not set to us, and now it's NO_NEXT_HOP_PREFERENCE, it's a fallback to flooding, so we + // consider it unseen because we might need to handle it now + if (found->next_hop != NO_NEXT_HOP_PREFERENCE && found->next_hop != nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()) && + p->next_hop == NO_NEXT_HOP_PREFERENCE) { + seenRecently = false; + } + } + if (seenRecently) { LOG_DEBUG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x\n", p->from, p->to, p->id); } if (withUpdate) { - if (found != recentPackets.end()) { // delete existing to updated timestamp (re-insert) - recentPackets.erase(found); // as unsorted_set::iterator is const (can't update timestamp - so re-insert..) + if (found != recentPackets.end()) { // delete existing to updated timestamp and next-hop/relayed_by (re-insert) + recentPackets.erase(found); // as unsorted_set::iterator is const (can't update - so re-insert..) } recentPackets.insert(r); printPacket("Add packet record", p); @@ -77,4 +88,20 @@ void PacketHistory::clearExpiredRecentPackets() } LOG_DEBUG("recentPackets size=%ld (after clearing expired packets)\n", recentPackets.size()); +} + +/* Find the relayer of a packet in the history given an ID and sender + * @return the 1-byte relay identifier, or NULL if not found */ +uint8_t PacketHistory::getRelayerFromHistory(const uint32_t id, const NodeNum sender) +{ + PacketRecord r; + r.id = id; + r.sender = sender; + auto found = recentPackets.find(r); + + if (found == recentPackets.end()) { + return NULL; + } + + return found->relayed_by; } \ No newline at end of file diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index 89d237a027..25fd7a2ab3 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -13,6 +13,8 @@ struct PacketRecord { NodeNum sender; PacketId id; uint32_t rxTimeMsec; // Unix time in msecs - the time we received it + uint8_t next_hop; // The next hop asked for this packet + uint8_t relayed_by; // The node that relayed this packet bool operator==(const PacketRecord &p) const { return sender == p.sender && id == p.id; } }; @@ -42,4 +44,8 @@ class PacketHistory * @param withUpdate if true and not found we add an entry to recentPackets */ bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true); -}; + + /* Find the relayer of a packet in the history given an ID and sender + * @return the 1-byte relay identifier, or NULL if not found */ + uint8_t getRelayerFromHistory(const uint32_t id, const NodeNum sender); +}; \ No newline at end of file diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index a3ea26509e..b21ce0d0ab 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -396,8 +396,9 @@ void RadioLibInterface::handleReceiveInterrupt() mp->hop_start = (h->flags & PACKET_FLAGS_HOP_START_MASK) >> PACKET_FLAGS_HOP_START_SHIFT; mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK); mp->via_mqtt = !!(h->flags & PACKET_FLAGS_VIA_MQTT_MASK); - mp->next_hop = h->next_hop; - mp->relay_node = h->relay_node; + // If hop_start is not set, next_hop and relay_node are invalid (firmware <2.3) + mp->next_hop = mp->hop_start == 0 ? NO_NEXT_HOP_PREFERENCE : h->next_hop; + mp->relay_node = mp->hop_start == 0 ? NO_NEXT_HOP_PREFERENCE : h->relay_node; addReceiveMetadata(mp); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index a4bc9b431a..d50ebaa649 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -35,7 +35,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) } } - return (config.lora.next_hop_routing && p->to != NODENUM_BROADCAST) ? NextHopRouter::send(p) : FloodingRouter::send(p); + return p->to == NODENUM_BROADCAST ? FloodingRouter::send(p) : NextHopRouter::send(p); } bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index c1ff7ebd49..3f4d378beb 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -32,9 +32,7 @@ typedef enum _meshtastic_AdminMessage_ConfigType { /* TODO: REPLACE */ meshtastic_AdminMessage_ConfigType_BLUETOOTH_CONFIG = 6, /* TODO: REPLACE */ - meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG = 7, - /* */ - meshtastic_AdminMessage_ConfigType_SESSIONKEY_CONFIG = 8 + meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG = 7 } meshtastic_AdminMessage_ConfigType; /* TODO: REPLACE */ @@ -206,8 +204,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_AdminMessage_ConfigType_MIN meshtastic_AdminMessage_ConfigType_DEVICE_CONFIG -#define _meshtastic_AdminMessage_ConfigType_MAX meshtastic_AdminMessage_ConfigType_SESSIONKEY_CONFIG -#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_SESSIONKEY_CONFIG+1)) +#define _meshtastic_AdminMessage_ConfigType_MAX meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG +#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG+1)) #define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG #define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG @@ -322,8 +320,7 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulato X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_seconds), 97) \ X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_config,factory_reset_config), 99) \ -X(a, STATIC, ONEOF, INT32, (payload_variant,nodedb_reset,nodedb_reset), 100) \ -X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) +X(a, STATIC, ONEOF, INT32, (payload_variant,nodedb_reset,nodedb_reset), 100) #define meshtastic_AdminMessage_CALLBACK NULL #define meshtastic_AdminMessage_DEFAULT NULL #define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel @@ -373,4 +370,4 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg; } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/config.pb.cpp b/src/mesh/generated/meshtastic/config.pb.cpp index 92c3313bdc..62c3de3324 100644 --- a/src/mesh/generated/meshtastic/config.pb.cpp +++ b/src/mesh/generated/meshtastic/config.pb.cpp @@ -33,23 +33,4 @@ PB_BIND(meshtastic_Config_LoRaConfig, meshtastic_Config_LoRaConfig, 2) PB_BIND(meshtastic_Config_BluetoothConfig, meshtastic_Config_BluetoothConfig, AUTO) -PB_BIND(meshtastic_Config_SecurityConfig, meshtastic_Config_SecurityConfig, AUTO) - - -PB_BIND(meshtastic_Config_SessionkeyConfig, meshtastic_Config_SessionkeyConfig, AUTO) - - - - - - - - - - - - - - - - +PB_BIND(meshtastic_Config_SecurityConfig, meshtastic_Config_SecurityConfig, AUTO) \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index cfecc858de..43cc73568c 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -284,6 +284,10 @@ typedef struct _meshtastic_Config_DeviceConfig { /* Disabling this will disable the SerialConsole by not initilizing the StreamAPI Moved to SecurityConfig */ bool serial_enabled; + /* By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). + Set this to true to leave the debug log outputting even when API is active. + Moved to SecurityConfig */ + bool debug_log_enabled; /* For boards without a hard wired button, this is the pin number that will be used Boards that have more than one button can swap the function with this one. defaults to BUTTON_PIN if defined. */ uint32_t button_gpio; @@ -501,8 +505,6 @@ 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; /* If true, disable the build-in PA FAN using pin define in RF95_FAN_EN. */ bool pa_fan_disabled; /* For testing it is useful sometimes to force a node to never listen to @@ -521,6 +523,9 @@ typedef struct _meshtastic_Config_BluetoothConfig { meshtastic_Config_BluetoothConfig_PairingMode mode; /* Specified PIN for PairingMode.FixedPin */ uint32_t fixed_pin; + /* Enables device (serial style logs) over Bluetooth + Moved to SecurityConfig */ + bool device_logging_enabled; } meshtastic_Config_BluetoothConfig; typedef PB_BYTES_ARRAY_T(32) meshtastic_Config_SecurityConfig_public_key_t; @@ -534,25 +539,21 @@ typedef struct _meshtastic_Config_SecurityConfig { Used to create a shared key with a remote device. */ meshtastic_Config_SecurityConfig_private_key_t private_key; /* The public key authorized to send admin messages to this node. */ - pb_size_t admin_key_count; - meshtastic_Config_SecurityConfig_admin_key_t admin_key[1]; + meshtastic_Config_SecurityConfig_admin_key_t admin_key; /* If true, device is considered to be "managed" by a mesh administrator via admin messages Device is managed by a mesh administrator. */ bool is_managed; /* Serial Console over the Stream API." */ bool serial_enabled; /* By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - Output live debug logging over serial or bluetooth is set to true. */ + Output live debug logging over serial. */ bool debug_log_api_enabled; + /* Enables device (serial style logs) over Bluetooth */ + bool bluetooth_logging_enabled; /* Allow incoming device control over the insecure legacy admin channel. */ bool admin_channel_enabled; } meshtastic_Config_SecurityConfig; -/* Blank config request, strictly for getting the session key */ -typedef struct _meshtastic_Config_SessionkeyConfig { - char dummy_field; -} meshtastic_Config_SessionkeyConfig; - typedef struct _meshtastic_Config { pb_size_t which_payload_variant; union { @@ -564,7 +565,6 @@ typedef struct _meshtastic_Config { meshtastic_Config_LoRaConfig lora; meshtastic_Config_BluetoothConfig bluetooth; meshtastic_Config_SecurityConfig security; - meshtastic_Config_SessionkeyConfig sessionkey; } payload_variant; } meshtastic_Config; @@ -649,7 +649,6 @@ extern "C" { - /* Initializer values for message structs */ #define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}} #define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} @@ -659,9 +658,8 @@ extern "C" { #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, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} #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}, 0} -#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} -#define meshtastic_Config_SecurityConfig_init_default {{0, {0}}, {0, {0}}, 0, {{0, {0}}}, 0, 0, 0, 0} -#define meshtastic_Config_SessionkeyConfig_init_default {0} +#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} +#define meshtastic_Config_SecurityConfig_init_default {{0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 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, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} @@ -670,9 +668,8 @@ extern "C" { #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, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} #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}, 0} -#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} -#define meshtastic_Config_SecurityConfig_init_zero {{0, {0}}, {0, {0}}, 0, {{0, {0}}}, 0, 0, 0, 0} -#define meshtastic_Config_SessionkeyConfig_init_zero {0} +#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} +#define meshtastic_Config_SecurityConfig_init_zero {{0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_Config_DeviceConfig_role_tag 1 @@ -745,19 +742,20 @@ 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_pa_fan_disabled_tag 16 +#define meshtastic_Config_LoRaConfig_pa_fan_disabled_tag 15 #define meshtastic_Config_LoRaConfig_ignore_incoming_tag 103 #define meshtastic_Config_LoRaConfig_ignore_mqtt_tag 104 #define meshtastic_Config_BluetoothConfig_enabled_tag 1 #define meshtastic_Config_BluetoothConfig_mode_tag 2 #define meshtastic_Config_BluetoothConfig_fixed_pin_tag 3 +#define meshtastic_Config_BluetoothConfig_device_logging_enabled_tag 4 #define meshtastic_Config_SecurityConfig_public_key_tag 1 #define meshtastic_Config_SecurityConfig_private_key_tag 2 #define meshtastic_Config_SecurityConfig_admin_key_tag 3 #define meshtastic_Config_SecurityConfig_is_managed_tag 4 #define meshtastic_Config_SecurityConfig_serial_enabled_tag 5 #define meshtastic_Config_SecurityConfig_debug_log_api_enabled_tag 6 +#define meshtastic_Config_SecurityConfig_bluetooth_logging_enabled_tag 7 #define meshtastic_Config_SecurityConfig_admin_channel_enabled_tag 8 #define meshtastic_Config_device_tag 1 #define meshtastic_Config_position_tag 2 @@ -767,7 +765,6 @@ extern "C" { #define meshtastic_Config_lora_tag 6 #define meshtastic_Config_bluetooth_tag 7 #define meshtastic_Config_security_tag 8 -#define meshtastic_Config_sessionkey_tag 9 /* Struct field encoding specification for nanopb */ #define meshtastic_Config_FIELDLIST(X, a) \ @@ -778,8 +775,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,network,payload_variant.netw X(a, STATIC, ONEOF, MESSAGE, (payload_variant,display,payload_variant.display), 5) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,lora,payload_variant.lora), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,bluetooth,payload_variant.bluetooth), 7) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,security,payload_variant.security), 8) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,sessionkey,payload_variant.sessionkey), 9) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,security,payload_variant.security), 8) #define meshtastic_Config_CALLBACK NULL #define meshtastic_Config_DEFAULT NULL #define meshtastic_Config_payload_variant_device_MSGTYPE meshtastic_Config_DeviceConfig @@ -790,7 +786,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,sessionkey,payload_variant.s #define meshtastic_Config_payload_variant_lora_MSGTYPE meshtastic_Config_LoRaConfig #define meshtastic_Config_payload_variant_bluetooth_MSGTYPE meshtastic_Config_BluetoothConfig #define meshtastic_Config_payload_variant_security_MSGTYPE meshtastic_Config_SecurityConfig -#define meshtastic_Config_payload_variant_sessionkey_MSGTYPE meshtastic_Config_SessionkeyConfig #define meshtastic_Config_DeviceConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, role, 1) \ @@ -888,8 +883,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, SINGULAR, BOOL, pa_fan_disabled, 16) \ +X(a, STATIC, SINGULAR, BOOL, pa_fan_disabled, 15) \ X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \ X(a, STATIC, SINGULAR, BOOL, ignore_mqtt, 104) #define meshtastic_Config_LoRaConfig_CALLBACK NULL @@ -898,26 +892,23 @@ X(a, STATIC, SINGULAR, BOOL, ignore_mqtt, 104) #define meshtastic_Config_BluetoothConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, UENUM, mode, 2) \ -X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3) +X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3) \ +X(a, STATIC, SINGULAR, BOOL, device_logging_enabled, 4) #define meshtastic_Config_BluetoothConfig_CALLBACK NULL #define meshtastic_Config_BluetoothConfig_DEFAULT NULL #define meshtastic_Config_SecurityConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BYTES, public_key, 1) \ X(a, STATIC, SINGULAR, BYTES, private_key, 2) \ -X(a, STATIC, REPEATED, BYTES, admin_key, 3) \ +X(a, STATIC, SINGULAR, BYTES, admin_key, 3) \ X(a, STATIC, SINGULAR, BOOL, is_managed, 4) \ X(a, STATIC, SINGULAR, BOOL, serial_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, debug_log_api_enabled, 6) \ +X(a, STATIC, SINGULAR, BOOL, bluetooth_logging_enabled, 7) \ X(a, STATIC, SINGULAR, BOOL, admin_channel_enabled, 8) #define meshtastic_Config_SecurityConfig_CALLBACK NULL #define meshtastic_Config_SecurityConfig_DEFAULT NULL -#define meshtastic_Config_SessionkeyConfig_FIELDLIST(X, a) \ - -#define meshtastic_Config_SessionkeyConfig_CALLBACK NULL -#define meshtastic_Config_SessionkeyConfig_DEFAULT NULL - extern const pb_msgdesc_t meshtastic_Config_msg; extern const pb_msgdesc_t meshtastic_Config_DeviceConfig_msg; extern const pb_msgdesc_t meshtastic_Config_PositionConfig_msg; @@ -928,7 +919,6 @@ extern const pb_msgdesc_t meshtastic_Config_DisplayConfig_msg; extern const pb_msgdesc_t meshtastic_Config_LoRaConfig_msg; extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; extern const pb_msgdesc_t meshtastic_Config_SecurityConfig_msg; -extern const pb_msgdesc_t meshtastic_Config_SessionkeyConfig_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_Config_fields &meshtastic_Config_msg @@ -941,24 +931,22 @@ extern const pb_msgdesc_t meshtastic_Config_SessionkeyConfig_msg; #define meshtastic_Config_LoRaConfig_fields &meshtastic_Config_LoRaConfig_msg #define meshtastic_Config_BluetoothConfig_fields &meshtastic_Config_BluetoothConfig_msg #define meshtastic_Config_SecurityConfig_fields &meshtastic_Config_SecurityConfig_msg -#define meshtastic_Config_SessionkeyConfig_fields &meshtastic_Config_SessionkeyConfig_msg /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size -#define meshtastic_Config_BluetoothConfig_size 10 -#define meshtastic_Config_DeviceConfig_size 98 +#define meshtastic_Config_BluetoothConfig_size 12 +#define meshtastic_Config_DeviceConfig_size 100 #define meshtastic_Config_DisplayConfig_size 30 -#define meshtastic_Config_LoRaConfig_size 84 +#define meshtastic_Config_LoRaConfig_size 82 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 #define meshtastic_Config_PositionConfig_size 62 #define meshtastic_Config_PowerConfig_size 52 -#define meshtastic_Config_SecurityConfig_size 111 -#define meshtastic_Config_SessionkeyConfig_size 0 +#define meshtastic_Config_SecurityConfig_size 112 #define meshtastic_Config_size 199 #ifdef __cplusplus } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 10687ba4e8..ce95a30d4c 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -360,10 +360,9 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; /* Maximum encoded size of messages (where known) */ /* meshtastic_DeviceState_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size - #define meshtastic_ChannelFile_size 718 -#define meshtastic_NodeInfoLite_size 183 -#define meshtastic_OEMStore_size 3497 +#define meshtastic_NodeInfoLite_size 203 +#define meshtastic_OEMStore_size 3502 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 96 @@ -371,4 +370,4 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 91a23dc4f4..0ede1aee2f 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -187,11 +187,11 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 664 +#define meshtastic_LocalConfig_size 669 #define meshtastic_LocalModuleConfig_size 687 #ifdef __cplusplus } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 5851d56a8c..5c1baef22e 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -180,25 +180,6 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_SENSECAP_INDICATOR = 70, /* Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. */ meshtastic_HardwareModel_TRACKER_T1000_E = 71, - /* RAK3172 STM32WLE5 Module (https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172) */ - meshtastic_HardwareModel_RAK3172 = 72, - /* Seeed Studio Wio-E5 (either mini or Dev kit) using STM32WL chip. */ - meshtastic_HardwareModel_WIO_E5 = 73, - /* RadioMaster 900 Bandit, https://www.radiomasterrc.com/products/bandit-expresslrs-rf-module - SSD1306 OLED and No GPS */ - meshtastic_HardwareModel_RADIOMASTER_900_BANDIT = 74, - /* Minewsemi ME25LS01 (ME25LE01_V1.0). NRF52840 w/ LR1110 radio, buttons and leds and pins. */ - meshtastic_HardwareModel_ME25LS01_4Y10TD = 75, - /* RP2040_FEATHER_RFM95 - Adafruit Feather RP2040 with RFM95 LoRa Radio RFM95 with SX1272, SSD1306 OLED - https://www.adafruit.com/product/5714 - https://www.adafruit.com/product/326 - https://www.adafruit.com/product/938 - ^^^ short A0 to switch to I2C address 0x3C */ - meshtastic_HardwareModel_RP2040_FEATHER_RFM95 = 76, - /* M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ */ - meshtastic_HardwareModel_M5STACK_COREBASIC = 77, - meshtastic_HardwareModel_M5STACK_CORE2 = 78, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -693,6 +674,10 @@ typedef struct _meshtastic_MeshPacket { /* Hop limit with which the original packet started. Sent via LoRa using three bits in the unencrypted header. When receiving a packet, the difference between hop_start and hop_limit gives how many hops it traveled. */ uint8_t hop_start; + /* Records the public key the packet was encrypted with, if applicable. */ + meshtastic_MeshPacket_public_key_t public_key; + /* Indicates whether the packet was en/decrypted using PKI */ + bool pki_encrypted; /* Last byte of the node number of the node that should be used as the next hop in routing. */ uint8_t next_hop; /* Last byte of the node number of the node that will relay/relayed this packet. */ @@ -1084,12 +1069,12 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_Position_init_default {false, 0, false, 0, false, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, false, 0, false, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}} #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 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, 0, 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, 0, 0, {0, {0}}, 0, 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, 0, 0, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0} #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1109,12 +1094,12 @@ extern "C" { #define meshtastic_ChunkedPayloadResponse_init_default {0, 0, {0}} #define meshtastic_Position_init_zero {false, 0, false, 0, false, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, false, 0, false, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}} #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 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, 0, 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, 0, 0, {0, {0}}, 0, 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, 0, 0, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0} #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1207,10 +1192,10 @@ extern "C" { #define meshtastic_MeshPacket_delayed_tag 13 #define meshtastic_MeshPacket_via_mqtt_tag 14 #define meshtastic_MeshPacket_hop_start_tag 15 -#define meshtastic_MeshPacket_next_hop_tag 16 -#define meshtastic_MeshPacket_relay_node_tag 17 -#define meshtastic_MeshPacket_public_key_tag 18 -#define meshtastic_MeshPacket_pki_encrypted_tag 19 +#define meshtastic_MeshPacket_public_key_tag 16 +#define meshtastic_MeshPacket_pki_encrypted_tag 17 +#define meshtastic_MeshPacket_next_hop_tag 18 +#define meshtastic_MeshPacket_relay_node_tag 19 #define meshtastic_NodeInfo_num_tag 1 #define meshtastic_NodeInfo_user_tag 2 #define meshtastic_NodeInfo_position_tag 3 @@ -1397,10 +1382,10 @@ X(a, STATIC, SINGULAR, INT32, rx_rssi, 12) \ X(a, STATIC, SINGULAR, UENUM, delayed, 13) \ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 14) \ X(a, STATIC, SINGULAR, UINT32, hop_start, 15) \ -X(a, STATIC, SINGULAR, UINT32, next_hop, 16) \ -X(a, STATIC, SINGULAR, UINT32, relay_node, 17) -X(a, STATIC, SINGULAR, BYTES, public_key, 18) \ -X(a, STATIC, SINGULAR, BOOL, pki_encrypted, 19) +X(a, STATIC, SINGULAR, BYTES, public_key, 16) \ +X(a, STATIC, SINGULAR, BOOL, pki_encrypted, 17) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 18) \ +X(a, STATIC, SINGULAR, UINT32, relay_node, 19) #define meshtastic_MeshPacket_CALLBACK NULL #define meshtastic_MeshPacket_DEFAULT NULL #define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data @@ -1643,7 +1628,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 #define meshtastic_LogRecord_size 426 -#define meshtastic_MeshPacket_size 364 +#define meshtastic_MeshPacket_size 372 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 18 #define meshtastic_NeighborInfo_size 258 @@ -1662,4 +1647,4 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index cedc2867e0..17fe4ee7da 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -283,14 +283,12 @@ extern "C" { #define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} #define meshtastic_Nau7802Config_init_zero {0, 0} @@ -464,7 +462,6 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 #define meshtastic_EnvironmentMetrics_size 85 -#define meshtastic_LocalStats_size 42 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 #define meshtastic_Telemetry_size 92 @@ -473,4 +470,4 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index bfe3a9ba50..bddeb8820d 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -186,7 +186,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta break; } case meshtastic_AdminMessage_factory_reset_config_tag: { - LOG_INFO("Initiating factory config reset\n"); + LOG_INFO("Initiating factory reset\n"); nodeDB->factoryReset(); reboot(DEFAULT_REBOOT_SECONDS); break; @@ -1028,4 +1028,4 @@ bool AdminModule::messageIsRequest(meshtastic_AdminMessage *r) return true; else return false; -} +} \ No newline at end of file diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index eca0e8ac91..3debb1ddf7 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -148,18 +148,8 @@ void setupModules() delete upDownInterruptImpl1; upDownInterruptImpl1 = nullptr; } - -#if HAS_SCREEN - // In order to have the user button dismiss the canned message frame, this class lightly interacts with the Screen class - scanAndSelectInput = new ScanAndSelectInput(); - if (!scanAndSelectInput->init()) { - delete scanAndSelectInput; - scanAndSelectInput = nullptr; - } -#endif - - cardKbI2cImpl = new CardKbI2cImpl(); - cardKbI2cImpl->init(); + // cardKbI2cImpl = new CardKbI2cImpl(); + // cardKbI2cImpl->init(); #ifdef INPUTBROKER_MATRIX_TYPE kbMatrixImpl = new KbMatrixImpl(); kbMatrixImpl->init(); diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index cb047a4dc0..2c162d297b 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -91,7 +91,7 @@ NodeInfoModule::NodeInfoModule() : ProtobufModule("nodeinfo", meshtastic_PortNum_NODEINFO_APP, &meshtastic_User_msg), concurrency::OSThread("NodeInfoModule") { isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others - setIntervalFromNow(30 * + setIntervalFromNow(20 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup) } diff --git a/src/modules/Telemetry/DeviceTelemetry.h b/src/modules/Telemetry/DeviceTelemetry.h index 6d7f698911..a25d165d53 100644 --- a/src/modules/Telemetry/DeviceTelemetry.h +++ b/src/modules/Telemetry/DeviceTelemetry.h @@ -17,8 +17,7 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu { uptimeWrapCount = 0; uptimeLastMs = millis(); - nodeStatusObserver.observe(&nodeStatus->onNewStatus); - setIntervalFromNow(45 * 1000); // Wait until NodeInfo is sent + setIntervalFromNow(450000 * 1000); // Wait until NodeInfo is sent } virtual bool wantUIFrame() { return false; } @@ -60,4 +59,4 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu uint32_t uptimeWrapCount; uint32_t uptimeLastMs; -}; +}; \ No newline at end of file From ba4220fe50da8e375a4533f26a752fae66b70487 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 1 Nov 2024 17:02:04 +0100 Subject: [PATCH 10/32] Update protos, store multiple relayers --- src/main.cpp | 4 +- src/mesh/FloodingRouter.cpp | 2 +- src/mesh/FloodingRouter.h | 5 +- src/mesh/NextHopRouter.cpp | 74 +++++----- src/mesh/PacketHistory.cpp | 29 ++-- src/mesh/PacketHistory.h | 15 ++- src/mesh/PhoneAPI.cpp | 5 +- src/mesh/ReliableRouter.cpp | 127 +----------------- src/mesh/generated/meshtastic/admin.pb.h | 14 +- src/mesh/generated/meshtastic/config.pb.cpp | 4 - src/mesh/generated/meshtastic/config.pb.h | 71 +++------- src/mesh/generated/meshtastic/deviceonly.pb.h | 20 +-- src/mesh/generated/meshtastic/localonly.pb.h | 8 +- src/mesh/generated/meshtastic/mesh.pb.h | 31 +---- src/mesh/generated/meshtastic/telemetry.pb.h | 13 +- src/modules/Modules.cpp | 16 ++- src/modules/NodeInfoModule.cpp | 4 +- src/modules/Telemetry/DeviceTelemetry.h | 5 +- 18 files changed, 131 insertions(+), 316 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 41c32ea714..90f1712d7a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -786,8 +786,8 @@ void setup() LOG_DEBUG("Starting audio thread"); audioThread = new AudioThread(); #endif - - service.init(); + service = new MeshService(); + service->init(); // Now that the mesh service is created, create any modules setupModules(); diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index fa35e48ef1..ab6b7ca948 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -47,7 +47,7 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) { // do not flood direct message that is ACKed or replied to - LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast."); + LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast"); Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM } if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 0ed2b55823..646613914b 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -29,8 +29,6 @@ class FloodingRouter : public Router, protected PacketHistory { private: - bool isRebroadcaster(); - public: /** * Constructor @@ -58,4 +56,7 @@ class FloodingRouter : public Router, protected PacketHistory * Look for broadcasts we need to rebroadcast */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; + + // Return true if we are a rebroadcaster + bool isRebroadcaster(); }; \ No newline at end of file diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 08dcdf3930..0c60d2cd33 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -18,9 +18,11 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) wasSeenRecently(p); // FIXME, move this to a sniffSent method p->next_hop = getNextHop(p->to, p->relay_node); // set the next hop - LOG_DEBUG("Setting next hop for packet with dest %x to %x\n", p->to, p->next_hop); + LOG_DEBUG("Setting next hop for packet with dest %x to %x", p->to, p->next_hop); - if (p->next_hop != NO_NEXT_HOP_PREFERENCE && (p->want_ack || (p->to != p->next_hop && p->hop_limit > 0))) + // If it's from us, ReliableRouter already handles retransmissions. If a next hop is set and hop limit is not 0, start + // retransmissions + if (!isFromUs(p) && p->next_hop != NO_NEXT_HOP_PREFERENCE && p->hop_limit > 0) startRetransmission(packetPool.allocCopy(*p)); // start retransmission for relayed packet return Router::send(p); @@ -28,13 +30,15 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { - if (wasSeenRecently(p)) { // Note: this will also add a recent packet record - if (p->next_hop == nodeDB->getLastByteOfNodeNum(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"); - stopRetransmission(p->from, p->id); - Router::cancelSending(p->from, p->id); + if (wasSeenRecently(p)) { // Note: this will return false for a fallback to flooding + printPacket("Already seen, try stop re-Tx and cancel sending", p); + rxDupe++; + stopRetransmission(p->from, p->id); + if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && + config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { + // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! + if (Router::cancelSending(p->from, p->id)) + txRelayCanceled++; } return true; } @@ -45,44 +49,44 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { NodeNum ourNodeNum = getNodeNum(); - // TODO DMs are now usually not decoded! bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); if (isAckorReply) { // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is // not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the destination - if (p->to == ourNodeNum && p->from != 0) { - if (p->relay_node) { - // Check who was the original relayer of this packet - uint8_t original_relayer = PacketHistory::getRelayerFromHistory(p->decoded.request_id, p->to); - uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(ourNodeNum); - meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); - // Either original relayer and relayer of ACK are the same, or we were the relayer and the ACK came directly from + if (p->from != 0 && p->relay_node) { + uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(ourNodeNum); + meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); + if (origTx) { + // Either relayer of ACK was also a relayer of the packet, or we were the relayer and the ACK came directly from // the destination - if (origTx && original_relayer == p->relay_node || - original_relayer == ourRelayID && p->relay_node == nodeDB->getLastByteOfNodeNum(p->from)) { - LOG_DEBUG("Update next hop of 0x%x to 0x%x based on received ACK or reply.\n", p->from, p->relay_node); - origTx->next_hop = p->relay_node; + if (wasRelayer(p->relay_node, p->decoded.request_id, p->to) || + (wasRelayer(ourRelayID, p->decoded.request_id, p->to) && + p->relay_node == nodeDB->getLastByteOfNodeNum(p->from))) { + if (origTx->next_hop != p->relay_node) { + LOG_DEBUG("Update next hop of 0x%x to 0x%x based on ACK/reply", p->from, p->relay_node); + origTx->next_hop = p->relay_node; + } } } + if (!isToUs(p)) { + Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM + stopRetransmission(p->from, p->decoded.request_id); // stop retransmission for this packet + } } - - LOG_DEBUG("Receiving an ACK or reply, don't need to relay this packet anymore.\n"); - Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM - stopRetransmission(p->from, p->decoded.request_id); } - if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) { - if ((p->to != ourNodeNum) && (getFrom(p) != ourNodeNum)) { + if (isRebroadcaster()) { + if (!isToUs(p) && !isFromUs(p)) { if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(ourNodeNum)) { meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it - LOG_INFO("Relaying received message coming from %x\n", p->relay_node); + LOG_INFO("Relaying received message coming from %x", p->relay_node); tosend->hop_limit--; // bump down the hop count NextHopRouter::send(tosend); } // else don't relay } } else { - LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n"); + LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } // handle the packet as normal Router::sniffReceived(p, c); @@ -98,11 +102,11 @@ uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node) if (node) { // We are careful not to return the relay node as the next hop if (node->next_hop && node->next_hop != relay_node) { - LOG_DEBUG("Next hop for 0x%x is 0x%x\n", to, node->next_hop); + LOG_DEBUG("Next hop for 0x%x is 0x%x", to, node->next_hop); return node->next_hop; } else { if (node->next_hop) - LOG_WARN("Next hop for 0x%x is 0x%x, same as relayer; setting as no preference\n", to, node->next_hop); + LOG_WARN("Next hop for 0x%x is 0x%x, same as relayer; set no pref", to, node->next_hop); } } return NO_NEXT_HOP_PREFERENCE; @@ -180,8 +184,8 @@ int32_t NextHopRouter::doRetransmissions() // FIXME, handle 51 day rolloever here!!! if (p.nextTxMsec <= now) { if (p.numRetransmissions == 0) { - if (p.packet->from == getNodeNum()) { - LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, + if (isFromUs(p.packet)) { + LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x", p.packet->from, p.packet->to, p.packet->id); sendAckNak(meshtastic_Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); } @@ -189,10 +193,10 @@ int32_t NextHopRouter::doRetransmissions() stopRetransmission(it->first); stillValid = false; // just deleted it } else { - LOG_DEBUG("Sending retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, + LOG_DEBUG("Sending retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d", p.packet->from, p.packet->to, p.packet->id, p.numRetransmissions); - if (p.packet->to != NODENUM_BROADCAST) { + if (!isBroadcast(p.packet->to)) { if (p.numRetransmissions == 1) { // Last retransmission, reset next_hop (fallback to FloodingRouter) p.packet->next_hop = NO_NEXT_HOP_PREFERENCE; diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 1deb0e5fa3..142d2c302a 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -28,7 +28,7 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd r.sender = getFrom(p); r.rxTimeMsec = millis(); r.next_hop = p->next_hop; - r.relayed_by = p->relay_node; + r.relayed_by[0] = p->relay_node; auto found = recentPackets.find(r); bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently @@ -41,10 +41,10 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd } if (seenRecently) { - // If it was seen with a next-hop not set to us, and now it's NO_NEXT_HOP_PREFERENCE, it's a fallback to flooding, so we - // consider it unseen because we might need to handle it now + // If it was seen with a next-hop not set to us, relayer is still the same and now it's NO_NEXT_HOP_PREFERENCE, it's a + // fallback to flooding, so we consider it unseen because we might need to handle it now if (found->next_hop != NO_NEXT_HOP_PREFERENCE && found->next_hop != nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()) && - p->next_hop == NO_NEXT_HOP_PREFERENCE) { + found->relayed_by[0] == p->relay_node && p->next_hop == NO_NEXT_HOP_PREFERENCE) { seenRecently = false; } } @@ -55,7 +55,12 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd if (withUpdate) { if (found != recentPackets.end()) { // delete existing to updated timestamp and next-hop/relayed_by (re-insert) - recentPackets.erase(found); // as unsorted_set::iterator is const (can't update - so re-insert..) + // Add the existing relayed_by to the new record + for (uint8_t i = 0; i < NUM_RELAYERS - 1; i++) { + if (found->relayed_by[i]) + r.relayed_by[i + 1] = found->relayed_by[i]; + } + recentPackets.erase(found); // as unsorted_set::iterator is const (can't update - so re-insert..) } recentPackets.insert(r); printPacket("Add packet record", p); @@ -88,9 +93,9 @@ void PacketHistory::clearExpiredRecentPackets() LOG_DEBUG("recentPackets size=%ld (after clearing expired packets)", recentPackets.size()); } -/* Find the relayer of a packet in the history given an ID and sender - * @return the 1-byte relay identifier, or NULL if not found */ -uint8_t PacketHistory::getRelayerFromHistory(const uint32_t id, const NodeNum sender) +/* Check if a certain node was a relayer of a packet in the history given an ID and sender + * @return true if node was indeed a relayer, false if not */ +bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender) { PacketRecord r; r.id = id; @@ -98,8 +103,12 @@ uint8_t PacketHistory::getRelayerFromHistory(const uint32_t id, const NodeNum se auto found = recentPackets.find(r); if (found == recentPackets.end()) { - return NULL; + return false; } - return found->relayed_by; + for (uint8_t i = 0; i < NUM_RELAYERS; i++) { + if (found->relayed_by[i] == relayer) { + return true; + } + } } \ No newline at end of file diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index 25fd7a2ab3..f89462ea54 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -6,15 +6,18 @@ /// We clear our old flood record 10 minutes after we see the last of it #define FLOOD_EXPIRE_TIME (10 * 60 * 1000L) +#define NUM_RELAYERS \ + 3 // Number of relayer we keep track of. Use 3 to be efficient with memory alignment of PacketRecord to 16 bytes + /** * A record of a recent message broadcast */ struct PacketRecord { NodeNum sender; PacketId id; - uint32_t rxTimeMsec; // Unix time in msecs - the time we received it - uint8_t next_hop; // The next hop asked for this packet - uint8_t relayed_by; // The node that relayed this packet + uint32_t rxTimeMsec; // Unix time in msecs - the time we received it + uint8_t next_hop; // The next hop asked for this packet + uint8_t relayed_by[NUM_RELAYERS]; // Array of nodes that relayed this packet bool operator==(const PacketRecord &p) const { return sender == p.sender && id == p.id; } }; @@ -45,7 +48,7 @@ class PacketHistory */ bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true); - /* Find the relayer of a packet in the history given an ID and sender - * @return the 1-byte relay identifier, or NULL if not found */ - uint8_t getRelayerFromHistory(const uint32_t id, const NodeNum sender); + /* Check if a certain node was a relayer of a packet in the history given an ID and sender + * @return true if node was indeed a relayer, false if not */ + bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender); }; \ No newline at end of file diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 98db38c47b..a956373f11 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -596,10 +596,13 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p) { printPacket("PACKET FROM PHONE", &p); +// For use with the simulator, we should not ignore duplicate packets +#if !(defined(ARCH_PORTDUINO) && !HAS_RADIO) if (p.id > 0 && wasSeenRecently(p.id)) { LOG_DEBUG("Ignoring packet from phone, already seen recently"); return false; } +#endif if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] && Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) { @@ -636,4 +639,4 @@ int PhoneAPI::onNotify(uint32_t newValue) } return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one -} \ No newline at end of file +} diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index f59bb22f3e..ca6a199fc4 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -35,7 +35,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) } } - return p->to == NODENUM_BROADCAST ? FloodingRouter::send(p) : NextHopRouter::send(p); + return isBroadcast(p->to) ? FloodingRouter::send(p) : NextHopRouter::send(p); } bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) @@ -85,7 +85,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) Router::send(tosend); } - return p->to == NODENUM_BROADCAST ? FloodingRouter::shouldFilterReceived(p) : NextHopRouter::shouldFilterReceived(p); + return isBroadcast(p->to) ? FloodingRouter::shouldFilterReceived(p) : NextHopRouter::shouldFilterReceived(p); } /** @@ -144,126 +144,5 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas } // handle the packet as normal - FloodingRouter::sniffReceived(p, c); -} - -#define NUM_RETRANSMISSIONS 3 - -PendingPacket::PendingPacket(meshtastic_MeshPacket *p) -{ - packet = p; - numRetransmissions = NUM_RETRANSMISSIONS - 1; // We subtract one, because we assume the user just did the first send -} - -PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key) -{ - auto old = pending.find(key); // If we have an old record, someone messed up because id got reused - if (old != pending.end()) { - return &old->second; - } else - return NULL; -} -/** - * Stop any retransmissions we are doing of the specified node/packet ID pair - */ -bool ReliableRouter::stopRetransmission(NodeNum from, PacketId id) -{ - auto key = GlobalPacketId(from, id); - return stopRetransmission(key); -} - -bool ReliableRouter::stopRetransmission(GlobalPacketId key) -{ - auto old = findPendingPacket(key); - if (old) { - auto p = old->packet; - /* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue - to avoid canceling a transmission if it was ACKed super fast via MQTT */ - if (old->numRetransmissions < NUM_RETRANSMISSIONS - 1) { - // remove the 'original' (identified by originator and packet->id) from the txqueue and free it - cancelSending(getFrom(p), p->id); - // now free the pooled copy for retransmission too - packetPool.release(p); - } - auto numErased = pending.erase(key); - assert(numErased == 1); - return true; - } else - return false; -} - -/** - * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. - */ -PendingPacket *ReliableRouter::startRetransmission(meshtastic_MeshPacket *p) -{ - auto id = GlobalPacketId(p); - auto rec = PendingPacket(p); - - stopRetransmission(getFrom(p), p->id); - - setNextTx(&rec); - pending[id] = rec; - - return &pending[id]; -} - -/** - * Do any retransmissions that are scheduled (FIXME - for the time being called from loop) - */ -int32_t ReliableRouter::doRetransmissions() -{ - uint32_t now = millis(); - int32_t d = INT32_MAX; - - // FIXME, we should use a better datastructure rather than walking through this map. - // for(auto el: pending) { - for (auto it = pending.begin(), nextIt = it; it != pending.end(); it = nextIt) { - ++nextIt; // we use this odd pattern because we might be deleting it... - auto &p = it->second; - - bool stillValid = true; // assume we'll keep this record around - - // FIXME, handle 51 day rolloever here!!! - if (p.nextTxMsec <= now) { - if (p.numRetransmissions == 0) { - LOG_DEBUG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x", p.packet->from, p.packet->to, - p.packet->id); - sendAckNak(meshtastic_Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); - // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - stopRetransmission(it->first); - stillValid = false; // just deleted it - } else { - LOG_DEBUG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d", p.packet->from, p.packet->to, - p.packet->id, p.numRetransmissions); - - // 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)); - - // Queue again - --p.numRetransmissions; - setNextTx(&p); - } - } - - if (stillValid) { - // Update our desired sleep delay - int32_t t = p.nextTxMsec - now; - - d = min(t, d); - } - } - - return d; -} - -void ReliableRouter::setNextTx(PendingPacket *pending) -{ - assert(iface); - auto d = iface->getRetransmissionMsec(pending->packet); - pending->nextTxMsec = millis() + d; - LOG_DEBUG("Setting next retransmission in %u msecs: ", d); - printPacket("", pending->packet); - setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time + isBroadcast(p->to) ? FloodingRouter::sniffReceived(p, c) : NextHopRouter::sniffReceived(p, c); } \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index e5f1815a9c..d802eb3da2 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -33,15 +33,11 @@ typedef enum _meshtastic_AdminMessage_ConfigType { /* TODO: REPLACE */ meshtastic_AdminMessage_ConfigType_BLUETOOTH_CONFIG = 6, /* TODO: REPLACE */ -<<<<<<< HEAD - meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG = 7 -======= meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG = 7, /* */ meshtastic_AdminMessage_ConfigType_SESSIONKEY_CONFIG = 8, /* device-ui config */ meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG = 9 ->>>>>>> origin/master } meshtastic_AdminMessage_ConfigType; /* TODO: REPLACE */ @@ -219,13 +215,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_AdminMessage_ConfigType_MIN meshtastic_AdminMessage_ConfigType_DEVICE_CONFIG -<<<<<<< HEAD -#define _meshtastic_AdminMessage_ConfigType_MAX meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG -#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_SECURITY_CONFIG+1)) -======= #define _meshtastic_AdminMessage_ConfigType_MAX meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG #define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG+1)) ->>>>>>> origin/master #define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG #define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG @@ -346,7 +337,8 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulato X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_seconds), 97) \ X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_config,factory_reset_config), 99) \ -X(a, STATIC, ONEOF, INT32, (payload_variant,nodedb_reset,nodedb_reset), 100) +X(a, STATIC, ONEOF, INT32, (payload_variant,nodedb_reset,nodedb_reset), 100) \ +X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) #define meshtastic_AdminMessage_CALLBACK NULL #define meshtastic_AdminMessage_DEFAULT NULL #define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel @@ -398,4 +390,4 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg; } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/meshtastic/config.pb.cpp b/src/mesh/generated/meshtastic/config.pb.cpp index 5361aed3f8..23f4d542b9 100644 --- a/src/mesh/generated/meshtastic/config.pb.cpp +++ b/src/mesh/generated/meshtastic/config.pb.cpp @@ -33,9 +33,6 @@ PB_BIND(meshtastic_Config_LoRaConfig, meshtastic_Config_LoRaConfig, 2) PB_BIND(meshtastic_Config_BluetoothConfig, meshtastic_Config_BluetoothConfig, AUTO) -<<<<<<< HEAD -PB_BIND(meshtastic_Config_SecurityConfig, meshtastic_Config_SecurityConfig, AUTO) -======= PB_BIND(meshtastic_Config_SecurityConfig, meshtastic_Config_SecurityConfig, AUTO) @@ -69,4 +66,3 @@ PB_BIND(meshtastic_Config_SessionkeyConfig, meshtastic_Config_SessionkeyConfig, ->>>>>>> origin/master diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 707b9826e4..fab23ae34f 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -296,10 +296,6 @@ typedef struct _meshtastic_Config_DeviceConfig { /* Disabling this will disable the SerialConsole by not initilizing the StreamAPI Moved to SecurityConfig */ bool serial_enabled; - /* By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - Set this to true to leave the debug log outputting even when API is active. - Moved to SecurityConfig */ - bool debug_log_enabled; /* For boards without a hard wired button, this is the pin number that will be used Boards that have more than one button can swap the function with this one. defaults to BUTTON_PIN if defined. */ uint32_t button_gpio; @@ -537,9 +533,6 @@ typedef struct _meshtastic_Config_BluetoothConfig { meshtastic_Config_BluetoothConfig_PairingMode mode; /* Specified PIN for PairingMode.FixedPin */ uint32_t fixed_pin; - /* Enables device (serial style logs) over Bluetooth - Moved to SecurityConfig */ - bool device_logging_enabled; } meshtastic_Config_BluetoothConfig; typedef PB_BYTES_ARRAY_T(32) meshtastic_Config_SecurityConfig_public_key_t; @@ -553,26 +546,25 @@ typedef struct _meshtastic_Config_SecurityConfig { Used to create a shared key with a remote device. */ meshtastic_Config_SecurityConfig_private_key_t private_key; /* The public key authorized to send admin messages to this node. */ -<<<<<<< HEAD - meshtastic_Config_SecurityConfig_admin_key_t admin_key; -======= pb_size_t admin_key_count; meshtastic_Config_SecurityConfig_admin_key_t admin_key[3]; ->>>>>>> origin/master /* If true, device is considered to be "managed" by a mesh administrator via admin messages Device is managed by a mesh administrator. */ bool is_managed; /* Serial Console over the Stream API." */ bool serial_enabled; /* By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - Output live debug logging over serial. */ + Output live debug logging over serial or bluetooth is set to true. */ bool debug_log_api_enabled; - /* Enables device (serial style logs) over Bluetooth */ - bool bluetooth_logging_enabled; /* Allow incoming device control over the insecure legacy admin channel. */ bool admin_channel_enabled; } meshtastic_Config_SecurityConfig; +/* Blank config request, strictly for getting the session key */ +typedef struct _meshtastic_Config_SessionkeyConfig { + char dummy_field; +} meshtastic_Config_SessionkeyConfig; + typedef struct _meshtastic_Config { pb_size_t which_payload_variant; union { @@ -584,11 +576,8 @@ typedef struct _meshtastic_Config { meshtastic_Config_LoRaConfig lora; meshtastic_Config_BluetoothConfig bluetooth; meshtastic_Config_SecurityConfig security; -<<<<<<< HEAD -======= meshtastic_Config_SessionkeyConfig sessionkey; meshtastic_DeviceUIConfig device_ui; ->>>>>>> origin/master } payload_variant; } meshtastic_Config; @@ -673,6 +662,7 @@ extern "C" { + /* Initializer values for message structs */ #define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}} #define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} @@ -681,16 +671,10 @@ 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, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -<<<<<<< HEAD -#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}, 0} -#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} -#define meshtastic_Config_SecurityConfig_init_default {{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}, 0, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_SecurityConfig_init_default {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0} #define meshtastic_Config_SessionkeyConfig_init_default {0} ->>>>>>> origin/master #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, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} @@ -698,16 +682,10 @@ 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, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -<<<<<<< HEAD -#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}, 0} -#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} -#define meshtastic_Config_SecurityConfig_init_zero {{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}, 0, 0} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_SecurityConfig_init_zero {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0} #define meshtastic_Config_SessionkeyConfig_init_zero {0} ->>>>>>> origin/master /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_Config_DeviceConfig_role_tag 1 @@ -787,14 +765,12 @@ extern "C" { #define meshtastic_Config_BluetoothConfig_enabled_tag 1 #define meshtastic_Config_BluetoothConfig_mode_tag 2 #define meshtastic_Config_BluetoothConfig_fixed_pin_tag 3 -#define meshtastic_Config_BluetoothConfig_device_logging_enabled_tag 4 #define meshtastic_Config_SecurityConfig_public_key_tag 1 #define meshtastic_Config_SecurityConfig_private_key_tag 2 #define meshtastic_Config_SecurityConfig_admin_key_tag 3 #define meshtastic_Config_SecurityConfig_is_managed_tag 4 #define meshtastic_Config_SecurityConfig_serial_enabled_tag 5 #define meshtastic_Config_SecurityConfig_debug_log_api_enabled_tag 6 -#define meshtastic_Config_SecurityConfig_bluetooth_logging_enabled_tag 7 #define meshtastic_Config_SecurityConfig_admin_channel_enabled_tag 8 #define meshtastic_Config_device_tag 1 #define meshtastic_Config_position_tag 2 @@ -804,11 +780,8 @@ extern "C" { #define meshtastic_Config_lora_tag 6 #define meshtastic_Config_bluetooth_tag 7 #define meshtastic_Config_security_tag 8 -<<<<<<< HEAD -======= #define meshtastic_Config_sessionkey_tag 9 #define meshtastic_Config_device_ui_tag 10 ->>>>>>> origin/master /* Struct field encoding specification for nanopb */ #define meshtastic_Config_FIELDLIST(X, a) \ @@ -819,13 +792,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,network,payload_variant.netw X(a, STATIC, ONEOF, MESSAGE, (payload_variant,display,payload_variant.display), 5) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,lora,payload_variant.lora), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,bluetooth,payload_variant.bluetooth), 7) \ -<<<<<<< HEAD -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,security,payload_variant.security), 8) -======= X(a, STATIC, ONEOF, MESSAGE, (payload_variant,security,payload_variant.security), 8) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,sessionkey,payload_variant.sessionkey), 9) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,device_ui,payload_variant.device_ui), 10) ->>>>>>> origin/master #define meshtastic_Config_CALLBACK NULL #define meshtastic_Config_DEFAULT NULL #define meshtastic_Config_payload_variant_device_MSGTYPE meshtastic_Config_DeviceConfig @@ -836,11 +805,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,device_ui,payload_variant.de #define meshtastic_Config_payload_variant_lora_MSGTYPE meshtastic_Config_LoRaConfig #define meshtastic_Config_payload_variant_bluetooth_MSGTYPE meshtastic_Config_BluetoothConfig #define meshtastic_Config_payload_variant_security_MSGTYPE meshtastic_Config_SecurityConfig -<<<<<<< HEAD -======= #define meshtastic_Config_payload_variant_sessionkey_MSGTYPE meshtastic_Config_SessionkeyConfig #define meshtastic_Config_payload_variant_device_ui_MSGTYPE meshtastic_DeviceUIConfig ->>>>>>> origin/master #define meshtastic_Config_DeviceConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, role, 1) \ @@ -948,23 +914,26 @@ X(a, STATIC, SINGULAR, BOOL, config_ok_to_mqtt, 105) #define meshtastic_Config_BluetoothConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, UENUM, mode, 2) \ -X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3) \ -X(a, STATIC, SINGULAR, BOOL, device_logging_enabled, 4) +X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3) #define meshtastic_Config_BluetoothConfig_CALLBACK NULL #define meshtastic_Config_BluetoothConfig_DEFAULT NULL #define meshtastic_Config_SecurityConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BYTES, public_key, 1) \ X(a, STATIC, SINGULAR, BYTES, private_key, 2) \ -X(a, STATIC, SINGULAR, BYTES, admin_key, 3) \ +X(a, STATIC, REPEATED, BYTES, admin_key, 3) \ X(a, STATIC, SINGULAR, BOOL, is_managed, 4) \ X(a, STATIC, SINGULAR, BOOL, serial_enabled, 5) \ X(a, STATIC, SINGULAR, BOOL, debug_log_api_enabled, 6) \ -X(a, STATIC, SINGULAR, BOOL, bluetooth_logging_enabled, 7) \ X(a, STATIC, SINGULAR, BOOL, admin_channel_enabled, 8) #define meshtastic_Config_SecurityConfig_CALLBACK NULL #define meshtastic_Config_SecurityConfig_DEFAULT NULL +#define meshtastic_Config_SessionkeyConfig_FIELDLIST(X, a) \ + +#define meshtastic_Config_SessionkeyConfig_CALLBACK NULL +#define meshtastic_Config_SessionkeyConfig_DEFAULT NULL + extern const pb_msgdesc_t meshtastic_Config_msg; extern const pb_msgdesc_t meshtastic_Config_DeviceConfig_msg; extern const pb_msgdesc_t meshtastic_Config_PositionConfig_msg; @@ -975,6 +944,7 @@ extern const pb_msgdesc_t meshtastic_Config_DisplayConfig_msg; extern const pb_msgdesc_t meshtastic_Config_LoRaConfig_msg; extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; extern const pb_msgdesc_t meshtastic_Config_SecurityConfig_msg; +extern const pb_msgdesc_t meshtastic_Config_SessionkeyConfig_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_Config_fields &meshtastic_Config_msg @@ -987,27 +957,24 @@ extern const pb_msgdesc_t meshtastic_Config_SecurityConfig_msg; #define meshtastic_Config_LoRaConfig_fields &meshtastic_Config_LoRaConfig_msg #define meshtastic_Config_BluetoothConfig_fields &meshtastic_Config_BluetoothConfig_msg #define meshtastic_Config_SecurityConfig_fields &meshtastic_Config_SecurityConfig_msg +#define meshtastic_Config_SessionkeyConfig_fields &meshtastic_Config_SessionkeyConfig_msg /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size -#define meshtastic_Config_BluetoothConfig_size 12 -#define meshtastic_Config_DeviceConfig_size 100 +#define meshtastic_Config_BluetoothConfig_size 10 +#define meshtastic_Config_DeviceConfig_size 98 #define meshtastic_Config_DisplayConfig_size 30 #define meshtastic_Config_LoRaConfig_size 85 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 #define meshtastic_Config_PositionConfig_size 62 #define meshtastic_Config_PowerConfig_size 52 -<<<<<<< HEAD -#define meshtastic_Config_SecurityConfig_size 112 -======= #define meshtastic_Config_SecurityConfig_size 178 #define meshtastic_Config_SessionkeyConfig_size 0 ->>>>>>> origin/master #define meshtastic_Config_size 199 #ifdef __cplusplus } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index b3199d1f5f..d74c52f312 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -152,12 +152,12 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0} #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}} #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_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0} #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}} #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} @@ -228,14 +228,9 @@ 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, BOOL, via_mqtt, 8) \ -<<<<<<< HEAD -X(a, STATIC, SINGULAR, UINT32, hops_away, 9) \ +X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, UINT32, next_hop, 11) -======= -X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ -X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) ->>>>>>> origin/master #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -288,12 +283,7 @@ extern const pb_msgdesc_t meshtastic_ChannelFile_msg; /* meshtastic_DeviceState_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_ChannelFile_size #define meshtastic_ChannelFile_size 718 -<<<<<<< HEAD -#define meshtastic_NodeInfoLite_size 203 -#define meshtastic_OEMStore_size 3502 -======= -#define meshtastic_NodeInfoLite_size 183 ->>>>>>> origin/master +#define meshtastic_NodeInfoLite_size 186 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 96 @@ -301,4 +291,4 @@ extern const pb_msgdesc_t meshtastic_ChannelFile_msg; } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 4314f9f971..6409aef749 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -186,18 +186,12 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; #define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg /* Maximum encoded size of messages (where known) */ -<<<<<<< HEAD -#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 669 -#define meshtastic_LocalModuleConfig_size 687 -======= #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size #define meshtastic_LocalConfig_size 735 #define meshtastic_LocalModuleConfig_size 697 ->>>>>>> origin/master #ifdef __cplusplus } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 00ad447256..ac95da58d2 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -183,8 +183,6 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_SENSECAP_INDICATOR = 70, /* Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. */ meshtastic_HardwareModel_TRACKER_T1000_E = 71, -<<<<<<< HEAD -======= /* RAK3172 STM32WLE5 Module (https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172) */ meshtastic_HardwareModel_RAK3172 = 72, /* Seeed Studio Wio-E5 (either mini or Dev kit) using STM32WL chip. */ @@ -214,7 +212,6 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_MS24SF1 = 82, /* Lilygo TLora-C6 with the new ESP32-C6 MCU */ meshtastic_HardwareModel_TLORA_C6 = 83, ->>>>>>> origin/master /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -724,10 +721,6 @@ typedef struct _meshtastic_MeshPacket { uint8_t next_hop; /* Last byte of the node number of the node that will relay/relayed this packet. */ uint8_t relay_node; - /* Records the public key the packet was encrypted with, if applicable. */ - meshtastic_MeshPacket_public_key_t public_key; - /* Indicates whether the packet was en/decrypted using PKI */ - bool pki_encrypted; } meshtastic_MeshPacket; /* The bluetooth to device link: @@ -1119,20 +1112,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_Position_init_default {false, 0, false, 0, false, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, false, 0, false, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}} #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} -<<<<<<< HEAD #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, {0, {0}}, 0, 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, 0, 0, 0} -#define meshtastic_MyNodeInfo_init_default {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, 0, 0, {0, {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, 0, false, 0, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}} ->>>>>>> origin/master #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_default {0, 0, 0, 0} #define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}} @@ -1150,20 +1137,14 @@ extern "C" { #define meshtastic_ChunkedPayloadResponse_init_default {0, 0, {0}} #define meshtastic_Position_init_zero {false, 0, false, 0, false, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, false, 0, false, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}} #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} -<<<<<<< HEAD #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, {0, {0}}, 0, 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, 0, 0, 0} -#define meshtastic_MyNodeInfo_init_zero {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, 0, 0, {0, {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, 0, false, 0, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}} ->>>>>>> origin/master #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_zero {0, 0, 0, 0} #define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}} @@ -1699,11 +1680,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 #define meshtastic_LogRecord_size 426 -<<<<<<< HEAD -#define meshtastic_MeshPacket_size 372 -======= -#define meshtastic_MeshPacket_size 367 ->>>>>>> origin/master +#define meshtastic_MeshPacket_size 375 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 36 #define meshtastic_NeighborInfo_size 258 @@ -1722,4 +1699,4 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 0c8627fc84..309c01dc7e 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -315,25 +315,17 @@ extern "C" { #define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -<<<<<<< HEAD -#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -======= #define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0} ->>>>>>> origin/master #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -<<<<<<< HEAD -#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -======= #define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0} ->>>>>>> origin/master #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} #define meshtastic_Nau7802Config_init_zero {0, 0} @@ -530,11 +522,8 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define meshtastic_AirQualityMetrics_size 78 #define meshtastic_DeviceMetrics_size 27 #define meshtastic_EnvironmentMetrics_size 85 -<<<<<<< HEAD -======= #define meshtastic_HealthMetrics_size 11 #define meshtastic_LocalStats_size 60 ->>>>>>> origin/master #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 #define meshtastic_Telemetry_size 92 @@ -543,4 +532,4 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index bbb536dd5e..69211c76b8 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -152,8 +152,18 @@ void setupModules() delete upDownInterruptImpl1; upDownInterruptImpl1 = nullptr; } - // cardKbI2cImpl = new CardKbI2cImpl(); - // cardKbI2cImpl->init(); + +#if HAS_SCREEN + // In order to have the user button dismiss the canned message frame, this class lightly interacts with the Screen class + scanAndSelectInput = new ScanAndSelectInput(); + if (!scanAndSelectInput->init()) { + delete scanAndSelectInput; + scanAndSelectInput = nullptr; + } +#endif + + cardKbI2cImpl = new CardKbI2cImpl(); + cardKbI2cImpl->init(); #ifdef INPUTBROKER_MATRIX_TYPE kbMatrixImpl = new KbMatrixImpl(); kbMatrixImpl->init(); @@ -235,4 +245,4 @@ void setupModules() // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks routingModule = new RoutingModule(); -} \ No newline at end of file +} diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 083942d18d..4680203bee 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -97,7 +97,7 @@ NodeInfoModule::NodeInfoModule() : ProtobufModule("nodeinfo", meshtastic_PortNum_NODEINFO_APP, &meshtastic_User_msg), concurrency::OSThread("NodeInfoModule") { isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others - setIntervalFromNow(20 * + setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup) } @@ -112,4 +112,4 @@ int32_t NodeInfoModule::runOnce() sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) } return Default::getConfiguredOrDefaultMs(config.device.node_info_broadcast_secs, default_node_info_broadcast_secs); -} \ No newline at end of file +} diff --git a/src/modules/Telemetry/DeviceTelemetry.h b/src/modules/Telemetry/DeviceTelemetry.h index a25d165d53..6d7f698911 100644 --- a/src/modules/Telemetry/DeviceTelemetry.h +++ b/src/modules/Telemetry/DeviceTelemetry.h @@ -17,7 +17,8 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu { uptimeWrapCount = 0; uptimeLastMs = millis(); - setIntervalFromNow(450000 * 1000); // Wait until NodeInfo is sent + nodeStatusObserver.observe(&nodeStatus->onNewStatus); + setIntervalFromNow(45 * 1000); // Wait until NodeInfo is sent } virtual bool wantUIFrame() { return false; } @@ -59,4 +60,4 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu uint32_t uptimeWrapCount; uint32_t uptimeLastMs; -}; \ No newline at end of file +}; From 9de8d5ae660388475da67f5aa2073ffe40515918 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 1 Nov 2024 17:04:01 +0100 Subject: [PATCH 11/32] Remove next-hop update logic from NeighborInfoModule --- src/modules/NeighborInfoModule.cpp | 50 +----------------------------- src/modules/NeighborInfoModule.h | 8 ----- 2 files changed, 1 insertion(+), 57 deletions(-) diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 0a662708d4..124030832b 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -156,54 +156,6 @@ void NeighborInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtas pb_encode_to_bytes(p.decoded.payload.bytes, sizeof(p.decoded.payload.bytes), &meshtastic_NeighborInfo_msg, n); } -/* 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 = nodeDB->getLastByteOfNodeNum(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 = nodeDB->getLastByteOfNodeNum(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 = nodeDB->getLastByteOfNodeNum(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 (size_t i = 0; i < neighbors.size(); i++) { - if (neighbors[i].node_id == node_id) { - return true; - } - } - return false; -} - void NeighborInfoModule::resetNeighbors() { neighbors.clear(); @@ -258,4 +210,4 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen neighbors.push_back(new_nbr); } return &neighbors.back(); -} \ No newline at end of file +} diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h index d0d6dc2513..fb6a837854 100644 --- a/src/modules/NeighborInfoModule.h +++ b/src/modules/NeighborInfoModule.h @@ -63,14 +63,6 @@ class NeighborInfoModule : public ProtobufModule, priva Exception is when the packet came via MQTT */ virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return enabled && !p->via_mqtt; } - /* Update the next hop for nodes in the database. - * Based on our own neighbors, and the neighbors of our neighbors. - */ - void updateNextHops(meshtastic_NeighborInfo *np); - - /* Return true if the given node is a neighbor of us */ - bool isANeighbor(NodeNum node_id); - /* These are for debugging only */ void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np); void printNodeDBNeighbors(); From 01344835af6636f0cdc7b1b99621217369c82a0f Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 1 Nov 2024 19:32:49 +0100 Subject: [PATCH 12/32] Fix retransmissions --- src/mesh/NextHopRouter.cpp | 10 +++++----- src/mesh/NextHopRouter.h | 6 ++++-- src/mesh/ReliableRouter.cpp | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 0c60d2cd33..6894351159 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -18,7 +18,7 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) wasSeenRecently(p); // FIXME, move this to a sniffSent method p->next_hop = getNextHop(p->to, p->relay_node); // set the next hop - LOG_DEBUG("Setting next hop for packet with dest %x to %x", p->to, p->next_hop); + // LOG_DEBUG("Setting next hop for packet with dest %x to %x", p->to, p->next_hop); // If it's from us, ReliableRouter already handles retransmissions. If a next hop is set and hop limit is not 0, start // retransmissions @@ -102,7 +102,7 @@ uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node) if (node) { // We are careful not to return the relay node as the next hop if (node->next_hop && node->next_hop != relay_node) { - LOG_DEBUG("Next hop for 0x%x is 0x%x", to, node->next_hop); + // LOG_DEBUG("Next hop for 0x%x is 0x%x", to, node->next_hop); return node->next_hop; } else { if (node->next_hop) @@ -152,10 +152,10 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key) /** * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. */ -PendingPacket *NextHopRouter::startRetransmission(meshtastic_MeshPacket *p) +PendingPacket *NextHopRouter::startRetransmission(meshtastic_MeshPacket *p, uint8_t numReTx) { auto id = GlobalPacketId(p); - auto rec = PendingPacket(p, this->NUM_RETRANSMISSIONS); + auto rec = PendingPacket(p, numReTx); stopRetransmission(getFrom(p), p->id); @@ -203,7 +203,7 @@ int32_t NextHopRouter::doRetransmissions() // Also reset it in the nodeDB meshtastic_NodeInfoLite *sentTo = nodeDB->getMeshNode(p.packet->to); if (sentTo) { - LOG_WARN("Resetting next hop for packet with dest 0x%x\n", p.packet->to); + LOG_INFO("Resetting next hop for packet with dest 0x%x\n", p.packet->to); sentTo->next_hop = NO_NEXT_HOP_PREFERENCE; } FloodingRouter::send(packetPool.allocCopy(*p.packet)); diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 07185f0889..376182e6e2 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -76,10 +76,12 @@ class NextHopRouter : public FloodingRouter virtual int32_t runOnce() override { // Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation - auto d = doRetransmissions(); + doRetransmissions(); int32_t r = FloodingRouter::runOnce(); + // Also after calling runOnce there might be new packets to retransmit + auto d = doRetransmissions(); return min(d, r); } @@ -113,7 +115,7 @@ class NextHopRouter : public FloodingRouter /** * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. */ - PendingPacket *startRetransmission(meshtastic_MeshPacket *p); + PendingPacket *startRetransmission(meshtastic_MeshPacket *p, uint8_t numReTx = NUM_RETRANSMISSIONS); /** * Stop any retransmissions we are doing of the specified node/packet ID pair diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index ca6a199fc4..0d052f4821 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -23,7 +23,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) } auto copy = packetPool.allocCopy(*p); - startRetransmission(copy); + startRetransmission(copy, this->NUM_RETRANSMISSIONS); } /* If we have pending retransmissions, add the airtime of this packet to it, because during that time we cannot receive an From e4c98185d2a0668fa272fc78abe29e226085febe Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 2 Nov 2024 19:34:21 +0100 Subject: [PATCH 13/32] Improve ACKs for repeated packets and responses --- src/mesh/FloodingRouter.cpp | 37 ++++++++++++++++++++++++++++------- src/mesh/FloodingRouter.h | 4 ++++ src/mesh/MeshModule.cpp | 10 +++++----- src/mesh/MeshModule.h | 2 +- src/mesh/ReliableRouter.cpp | 28 +++++++++++--------------- src/mesh/Router.cpp | 5 ++--- src/mesh/Router.h | 3 +-- src/modules/RoutingModule.cpp | 5 ++--- src/modules/RoutingModule.h | 5 ++--- 9 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index ab6b7ca948..615a3be3d0 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -21,14 +21,27 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { + /* Resend implicit ACKs for repeated packets (hopStart equals hopLimit); + * 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. */ + bool isRepeated = p->hop_start > 0 && (p->hop_start == p->hop_limit); + bool didRebroadcast = false; + if (wasSeenRecently(p, false) && isRepeated) { + LOG_DEBUG("Repeated floodmsg"); + didRebroadcast = perhapsRebroadcast(p); // perhaps rebroadcast the packet + } + if (wasSeenRecently(p)) { // Note: this will also add a recent packet record printPacket("Ignoring dupe incoming msg", p); rxDupe++; - if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && - config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { - // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! - if (Router::cancelSending(p->from, p->id)) - txRelayCanceled++; + if (!didRebroadcast) { // We shouldn't cancel a rebroadcast that we just did + if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && + config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { + // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! + if (Router::cancelSending(p->from, p->id)) + txRelayCanceled++; + } } return true; } @@ -50,6 +63,14 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast"); Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM } + perhapsRebroadcast(p); + + // handle the packet as normal + Router::sniffReceived(p, c); +} + +bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) +{ if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { if (p->id != 0) { if (isRebroadcaster()) { @@ -68,6 +89,8 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas // Note: we are careful to resend using the original senders node id // We are careful not to call our hooked version of send() - because we don't want to check this again Router::send(tosend); + + return true; } else { LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } @@ -75,6 +98,6 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas LOG_DEBUG("Ignoring 0 id broadcast"); } } - // handle the packet as normal - Router::sniffReceived(p, c); + + return false; } \ No newline at end of file diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 646613914b..e0d0cee1e5 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -29,6 +29,10 @@ class FloodingRouter : public Router, protected PacketHistory { private: + /** Check if we should rebroadcast this packet, and do so if needed + * @return true if rebroadcasted */ + bool perhapsRebroadcast(const meshtastic_MeshPacket *p); + public: /** * Constructor diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index a8de540eb3..fc8199c658 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -33,7 +33,7 @@ MeshModule::~MeshModule() } meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, - uint8_t hopStart, uint8_t hopLimit) + uint8_t hopLimit) { meshtastic_Routing c = meshtastic_Routing_init_default; @@ -50,7 +50,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod p->priority = meshtastic_MeshPacket_Priority_ACK; - p->hop_limit = routingModule->getHopLimitForResponse(hopStart, hopLimit); // Flood ACK back to original sender + p->hop_limit = hopLimit; // Flood ACK back to original sender p->to = to; p->decoded.request_id = idFrom; p->channel = chIndex; @@ -181,8 +181,8 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src) // SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded) // but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs // bad. - routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel, mp.hop_start, - mp.hop_limit); + routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel, + routingModule->getHopLimitForResponse(mp.hop_start, mp.hop_limit)); } } @@ -295,4 +295,4 @@ bool MeshModule::isRequestingFocus() } else return false; } -#endif +#endif \ No newline at end of file diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index 7929ba972b..d37de0d830 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -162,7 +162,7 @@ class MeshModule virtual Observable *getUIFrameObservable() { return NULL; } meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, - uint8_t hopStart = 0, uint8_t hopLimit = 0); + uint8_t hopLimit = 0); /// Send an error response for the specified packet. meshtastic_MeshPacket *allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 0d052f4821..8b1ff2f121 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -1,10 +1,10 @@ #include "ReliableRouter.h" #include "Default.h" -#include "MeshModule.h" #include "MeshTypes.h" #include "configuration.h" #include "mesh-pb-constants.h" #include "modules/NodeInfoModule.h" +#include "modules/RoutingModule.h" // ReliableRouter::ReliableRouter() {} @@ -73,18 +73,6 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) i->second.nextTxMsec += iface->getPacketTime(p); } - /* Resend implicit ACKs for repeated packets (hopStart equals hopLimit); - * 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. */ - bool isRepeated = p->hop_start == 0 ? (p->hop_limit == HOP_RELIABLE) : (p->hop_start == p->hop_limit); - if (wasSeenRecently(p, false) && isRepeated && !MeshModule::currentReply && !isToUs(p)) { - LOG_DEBUG("Resending implicit ack for a repeated floodmsg"); - meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); - tosend->hop_limit--; // bump down the hop count - Router::send(tosend); - } - return isBroadcast(p->to) ? FloodingRouter::shouldFilterReceived(p) : NextHopRouter::shouldFilterReceived(p); } @@ -107,16 +95,22 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas if (MeshModule::currentReply) { LOG_DEBUG("Another module replied to this message, no need for 2nd ack"); } else if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, p->hop_start, p->hop_limit); + // A response may be set to want_ack for retransmissions, but we don't need to ACK a response if it received an + // implicit ACK already. If we received it directly, only ACK with a hop limit of 0 + if (!p->decoded.request_id) + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, + routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit)); + else if (p->hop_start > 0 && p->hop_start == p->hop_limit) + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); } else if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag && p->channel == 0 && (nodeDB->getMeshNode(p->from) == nullptr || nodeDB->getMeshNode(p->from)->user.public_key.size == 0)) { LOG_INFO("PKI packet from unknown node, send PKI_UNKNOWN_PUBKEY"); sendAckNak(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY, getFrom(p), p->id, channels.getPrimaryIndex(), - p->hop_start, p->hop_limit); + routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit)); } else { // Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded - sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(), p->hop_start, - p->hop_limit); + sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(), + routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit)); } } if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && c && diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 523d5ba116..e949e16a0c 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -133,10 +133,9 @@ meshtastic_MeshPacket *Router::allocForSending() /** * Send an ack or a nak packet back towards whoever sent idFrom */ -void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart, - uint8_t hopLimit) +void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit) { - routingModule->sendAckNak(err, to, idFrom, chIndex, hopStart, hopLimit); + routingModule->sendAckNak(err, to, idFrom, chIndex, hopLimit); } void Router::abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p) diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 8ebc1a3e53..4414b18598 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -108,8 +108,7 @@ class Router : protected concurrency::OSThread /** * Send an ack or a nak packet back towards whoever sent idFrom */ - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart = 0, - uint8_t hopLimit = 0); + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0); private: /** diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index f11a9a542f..5079aa5d86 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -49,10 +49,9 @@ meshtastic_MeshPacket *RoutingModule::allocReply() return NULL; } -void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart, - uint8_t hopLimit) +void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit) { - auto p = allocAckNak(err, to, idFrom, chIndex, hopStart, hopLimit); + auto p = allocAckNak(err, to, idFrom, chIndex, hopLimit); router->sendLocal(p); // we sometimes send directly to the local node } diff --git a/src/modules/RoutingModule.h b/src/modules/RoutingModule.h index f085b307bf..7c34c5bc97 100644 --- a/src/modules/RoutingModule.h +++ b/src/modules/RoutingModule.h @@ -13,8 +13,7 @@ class RoutingModule : public ProtobufModule */ RoutingModule(); - void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart = 0, - uint8_t hopLimit = 0); + void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0); // Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit); @@ -36,4 +35,4 @@ class RoutingModule : public ProtobufModule virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return true; } }; -extern RoutingModule *routingModule; +extern RoutingModule *routingModule; \ No newline at end of file From aab973e81bc21ab30fb3929478390dbce7876e81 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 2 Nov 2024 19:35:01 +0100 Subject: [PATCH 14/32] Stop retransmission even if there's not relay node --- src/mesh/NextHopRouter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 6894351159..7d1568f4c5 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -68,10 +68,10 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast } } } - if (!isToUs(p)) { - Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM - stopRetransmission(p->from, p->decoded.request_id); // stop retransmission for this packet - } + } + if (!isToUs(p)) { + Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM + stopRetransmission(p->from, p->decoded.request_id); // stop retransmission for this packet } } From 790801f8e7884e8b2ba2ae1f114c9d4fe5848be2 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 5 Nov 2024 18:57:50 +0100 Subject: [PATCH 15/32] Revert perhapsRebroadcast() --- src/mesh/FloodingRouter.cpp | 39 ++++++++----------------------------- src/mesh/FloodingRouter.h | 6 +----- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 549b652a84..9d7e4d8f69 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -21,27 +21,14 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { - /* Resend implicit ACKs for repeated packets (hopStart equals hopLimit); - * 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. */ - bool isRepeated = p->hop_start > 0 && (p->hop_start == p->hop_limit); - bool didRebroadcast = false; - if (wasSeenRecently(p, false) && isRepeated) { - LOG_DEBUG("Repeated floodmsg"); - didRebroadcast = perhapsRebroadcast(p); // perhaps rebroadcast the packet - } - if (wasSeenRecently(p)) { // Note: this will also add a recent packet record printPacket("Ignore dupe incoming msg", p); rxDupe++; - if (!didRebroadcast) { // We shouldn't cancel a rebroadcast that we just did - if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && - config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { - // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! - if (Router::cancelSending(p->from, p->id)) - txRelayCanceled++; - } + if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && + config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { + // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! + if (Router::cancelSending(p->from, p->id)) + txRelayCanceled++; } return true; } @@ -63,14 +50,6 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast"); Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM } - perhapsRebroadcast(p); - - // handle the packet as normal - Router::sniffReceived(p, c); -} - -bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) -{ if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { if (p->id != 0) { if (isRebroadcaster()) { @@ -89,8 +68,6 @@ bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) // Note: we are careful to resend using the original senders node id // We are careful not to call our hooked version of send() - because we don't want to check this again Router::send(tosend); - - return true; } else { LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } @@ -98,6 +75,6 @@ bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) LOG_DEBUG("Ignore 0 id broadcast"); } } - - return false; -} \ No newline at end of file + // handle the packet as normal + Router::sniffReceived(p, c); +} diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index e0d0cee1e5..11c2c47272 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -29,10 +29,6 @@ class FloodingRouter : public Router, protected PacketHistory { private: - /** Check if we should rebroadcast this packet, and do so if needed - * @return true if rebroadcasted */ - bool perhapsRebroadcast(const meshtastic_MeshPacket *p); - public: /** * Constructor @@ -63,4 +59,4 @@ class FloodingRouter : public Router, protected PacketHistory // Return true if we are a rebroadcaster bool isRebroadcaster(); -}; \ No newline at end of file +}; From bb64b1480b00c2a047fbbec75b9df151912f47e2 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 5 Nov 2024 19:40:00 +0100 Subject: [PATCH 16/32] Remove relayer if we cancel a transmission --- src/mesh/FloodingRouter.h | 5 ++--- src/mesh/PacketHistory.cpp | 30 +++++++++++++++++++++++++++++- src/mesh/PacketHistory.h | 5 ++++- src/mesh/Router.cpp | 9 +++++++-- src/mesh/Router.h | 3 ++- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 11c2c47272..25d674e6be 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -1,6 +1,5 @@ #pragma once -#include "PacketHistory.h" #include "Router.h" /** @@ -26,7 +25,7 @@ Any entries in recentBroadcasts that are older than X seconds (longer than the max time a flood can take) will be discarded. */ -class FloodingRouter : public Router, protected PacketHistory +class FloodingRouter : public Router { private: public: @@ -59,4 +58,4 @@ class FloodingRouter : public Router, protected PacketHistory // Return true if we are a rebroadcaster bool isRebroadcaster(); -}; +}; \ No newline at end of file diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 430ac6b995..91e395d9c9 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -70,7 +70,7 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd recentPackets.erase(found); // as unsorted_set::iterator is const (can't update - so re-insert..) } recentPackets.insert(r); - printPacket("Add packet record", p); + LOG_DEBUG("Add packet record fr=0x%x, id=0x%x", p->from, p->id); } // Capacity is reerved, so only purge expired packets if recentPackets fills past 90% capacity @@ -118,4 +118,32 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N return true; } } +} + +// Remove a relayer from the list of relayers of a packet in the history given an ID and sender +void PacketHistory::removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender) +{ + PacketRecord r; + r.id = id; + r.sender = sender; + auto found = recentPackets.find(r); + + if (found == recentPackets.end()) { + return; + } + // Make a copy of the found record + r.next_hop = found->next_hop; + r.rxTimeMsec = found->rxTimeMsec; + + // Only add the relayers that are not the one we want to remove + uint8_t j = 0; + for (uint8_t i = 0; i < NUM_RELAYERS; i++) { + if (found->relayed_by[i] != relayer) { + r.relayed_by[j] = found->relayed_by[i]; + j++; + } + } + + recentPackets.erase(found); + recentPackets.insert(r); } \ No newline at end of file diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index f89462ea54..adde4b27d9 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -1,6 +1,6 @@ #pragma once -#include "Router.h" +#include "NodeDB.h" #include /// We clear our old flood record 10 minutes after we see the last of it @@ -51,4 +51,7 @@ class PacketHistory /* Check if a certain node was a relayer of a packet in the history given an ID and sender * @return true if node was indeed a relayer, false if not */ bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender); + + // Remove a relayer from the list of relayers of a packet in the history given an ID and sender + void removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender); }; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 246612500a..5fa40d539f 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -290,7 +290,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ bool Router::cancelSending(NodeNum from, PacketId id) { - return iface ? iface->cancelSending(from, id) : false; + if (iface && iface->cancelSending(from, id)) { + // We are not a relayer of this packet anymore + removeRelayer(nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()), id, from); + return true; + } + return false; } /** @@ -672,4 +677,4 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) // cache/learn of the existence of nodes (i.e. FloodRouter) that they should not handleReceived(p); packetPool.release(p); -} +} \ No newline at end of file diff --git a/src/mesh/Router.h b/src/mesh/Router.h index da44d67df7..14ce4810b6 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -4,6 +4,7 @@ #include "MemoryPool.h" #include "MeshTypes.h" #include "Observer.h" +#include "PacketHistory.h" #include "PointerQueue.h" #include "RadioInterface.h" #include "concurrency/OSThread.h" @@ -11,7 +12,7 @@ /** * A mesh aware router that supports multiple interfaces. */ -class Router : protected concurrency::OSThread +class Router : protected concurrency::OSThread, protected PacketHistory { private: /// Packets which have just arrived from the radio, ready to be processed by this service and possibly From 24ff7c0bfb66ccba382c6c6adf0161650e2db177 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 5 Nov 2024 21:27:10 +0100 Subject: [PATCH 17/32] Better checking for fallback to flooding --- src/mesh/NextHopRouter.cpp | 6 +++--- src/mesh/PacketHistory.cpp | 24 +++++++++++++++++++----- src/mesh/PacketHistory.h | 4 ++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 7d1568f4c5..38cc0fe6d8 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -18,7 +18,7 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) wasSeenRecently(p); // FIXME, move this to a sniffSent method p->next_hop = getNextHop(p->to, p->relay_node); // set the next hop - // LOG_DEBUG("Setting next hop for packet with dest %x to %x", p->to, p->next_hop); + LOG_DEBUG("Setting next hop for packet with dest %x to %x", p->to, p->next_hop); // If it's from us, ReliableRouter already handles retransmissions. If a next hop is set and hop limit is not 0, start // retransmissions @@ -62,8 +62,8 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast if (wasRelayer(p->relay_node, p->decoded.request_id, p->to) || (wasRelayer(ourRelayID, p->decoded.request_id, p->to) && p->relay_node == nodeDB->getLastByteOfNodeNum(p->from))) { - if (origTx->next_hop != p->relay_node) { - LOG_DEBUG("Update next hop of 0x%x to 0x%x based on ACK/reply", p->from, p->relay_node); + if (origTx->next_hop != p->relay_node) { // Not already set + LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply", p->from, p->relay_node); origTx->next_hop = p->relay_node; } } diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 91e395d9c9..8d3ae36fc7 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -29,6 +29,7 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd r.rxTimeMsec = millis(); r.next_hop = p->next_hop; r.relayed_by[0] = p->relay_node; + LOG_INFO("Add relayed_by 0x%x for id=0x%x", p->relay_node, r.id); auto found = recentPackets.find(r); bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently @@ -48,10 +49,15 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd } if (seenRecently) { - // If it was seen with a next-hop not set to us, relayer is still the same and now it's NO_NEXT_HOP_PREFERENCE, it's a - // fallback to flooding, so we consider it unseen because we might need to handle it now - if (found->next_hop != NO_NEXT_HOP_PREFERENCE && found->next_hop != nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()) && - found->relayed_by[0] == p->relay_node && p->next_hop == NO_NEXT_HOP_PREFERENCE) { + // If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, relayer relayed already before, it's + // a fallback to flooding. If we didn't already relay and the next-hop neither, consider it unseen because we might need + // to handle it now + uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); + if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && + p->next_hop == NO_NEXT_HOP_PREFERENCE && found->next_hop != nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()) && + p->relay_node != 0 && wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && + !wasRelayer(found->next_hop, found)) { + LOG_WARN("Fallback to flooding, consider unseen relay_node=0x%x", p->relay_node); seenRecently = false; } } @@ -113,11 +119,19 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N return false; } + return wasRelayer(relayer, found); +} + +/* Check if a certain node was a relayer of a packet in the history given iterator + * @return true if node was indeed a relayer, false if not */ +bool PacketHistory::wasRelayer(const uint8_t relayer, std::unordered_set::iterator r) +{ for (uint8_t i = 0; i < NUM_RELAYERS; i++) { - if (found->relayed_by[i] == relayer) { + if (r->relayed_by[i] == relayer) { return true; } } + return false; } // Remove a relayer from the list of relayers of a packet in the history given an ID and sender diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index adde4b27d9..aae5ebff17 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -52,6 +52,10 @@ class PacketHistory * @return true if node was indeed a relayer, false if not */ bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender); + /* Check if a certain node was a relayer of a packet in the history given iterator + * @return true if node was indeed a relayer, false if not */ + bool wasRelayer(const uint8_t relayer, std::unordered_set::iterator r); + // Remove a relayer from the list of relayers of a packet in the history given an ID and sender void removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender); }; \ No newline at end of file From 69f88b9fdc07f49b76bbca1f407a70971c0c6b20 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Tue, 5 Nov 2024 21:28:02 +0100 Subject: [PATCH 18/32] Fix newlines in traceroute print logs --- src/modules/TraceRouteModule.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp index 79b14de0a2..d351acd10d 100644 --- a/src/modules/TraceRouteModule.cpp +++ b/src/modules/TraceRouteModule.cpp @@ -109,7 +109,7 @@ void TraceRouteModule::appendMyIDandSNR(meshtastic_RouteDiscovery *updated, floa void TraceRouteModule::printRoute(meshtastic_RouteDiscovery *r, uint32_t origin, uint32_t dest, bool isTowardsDestination) { #ifdef DEBUG_PORT - std::string route = "Route traced:"; + std::string route = "Route traced:\n"; route += vformat("0x%x --> ", origin); for (uint8_t i = 0; i < r->route_count; i++) { if (i < r->snr_towards_count && r->snr_towards[i] != INT8_MIN) @@ -129,6 +129,7 @@ void TraceRouteModule::printRoute(meshtastic_RouteDiscovery *r, uint32_t origin, // If there's a route back (or we are the destination as then the route is complete), print it if (r->route_back_count > 0 || origin == nodeDB->getNodeNum()) { + route += "\n"; if (r->snr_towards_count > 0 && origin == nodeDB->getNodeNum()) route += vformat("(%.2fdB) 0x%x <-- ", (float)r->snr_back[r->snr_back_count - 1] / 4, origin); else From 70aa28c53c00cf97d8f9b0bdb2b2c2077c7e5431 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 8 Nov 2024 21:28:19 +0100 Subject: [PATCH 19/32] Stop retransmission for original packet --- src/mesh/NextHopRouter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 38cc0fe6d8..c5bb5b87cd 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -71,7 +71,8 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast } if (!isToUs(p)) { Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM - stopRetransmission(p->from, p->decoded.request_id); // stop retransmission for this packet + // stop retransmission for the original packet + stopRetransmission(p->to, p->decoded.request_id); // for original packet, from = to and id = request_id } } From 78bf1e192bc13708902ac64e8dd3992b842c6b25 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 8 Nov 2024 21:28:36 +0100 Subject: [PATCH 20/32] Use relayID --- src/mesh/NextHopRouter.cpp | 14 ++++++-------- src/mesh/PacketHistory.cpp | 7 +++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index c5bb5b87cd..1ce9987208 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -49,12 +49,12 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { NodeNum ourNodeNum = getNodeNum(); + uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(ourNodeNum); bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); if (isAckorReply) { // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is // not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the destination if (p->from != 0 && p->relay_node) { - uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(ourNodeNum); meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); if (origTx) { // Either relayer of ACK was also a relayer of the packet, or we were the relayer and the ACK came directly from @@ -78,7 +78,7 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast if (isRebroadcaster()) { if (!isToUs(p) && !isFromUs(p)) { - if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(ourNodeNum)) { + if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == ourRelayID) { meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it LOG_INFO("Relaying received message coming from %x", p->relay_node); @@ -100,15 +100,13 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node) { meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(to); - if (node) { + if (node && node->next_hop) { // We are careful not to return the relay node as the next hop - if (node->next_hop && node->next_hop != relay_node) { + if (node->next_hop != relay_node) { // LOG_DEBUG("Next hop for 0x%x is 0x%x", to, node->next_hop); return node->next_hop; - } else { - if (node->next_hop) - LOG_WARN("Next hop for 0x%x is 0x%x, same as relayer; set no pref", to, node->next_hop); - } + } else + LOG_WARN("Next hop for 0x%x is 0x%x, same as relayer; set no pref", to, node->next_hop); } return NO_NEXT_HOP_PREFERENCE; } diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 8d3ae36fc7..5af5289996 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -54,9 +54,8 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd // to handle it now uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && - p->next_hop == NO_NEXT_HOP_PREFERENCE && found->next_hop != nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()) && - p->relay_node != 0 && wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && - !wasRelayer(found->next_hop, found)) { + p->next_hop == NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && p->relay_node != 0 && + wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) { LOG_WARN("Fallback to flooding, consider unseen relay_node=0x%x", p->relay_node); seenRecently = false; } @@ -160,4 +159,4 @@ void PacketHistory::removeRelayer(const uint8_t relayer, const uint32_t id, cons recentPackets.erase(found); recentPackets.insert(r); -} \ No newline at end of file +} From f37abe8f0f46fe129b5c92b3b2e4cdaefeecdf45 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 8 Nov 2024 21:42:54 +0100 Subject: [PATCH 21/32] Also when want_ack is set, we should try to retransmit --- src/mesh/NextHopRouter.cpp | 6 +++--- src/mesh/PacketHistory.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 1ce9987208..df86866e96 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -20,9 +20,9 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) p->next_hop = getNextHop(p->to, p->relay_node); // set the next hop LOG_DEBUG("Setting next hop for packet with dest %x to %x", p->to, p->next_hop); - // If it's from us, ReliableRouter already handles retransmissions. If a next hop is set and hop limit is not 0, start - // retransmissions - if (!isFromUs(p) && p->next_hop != NO_NEXT_HOP_PREFERENCE && p->hop_limit > 0) + // If it's from us, ReliableRouter already handles retransmissions. If a next hop is set and hop limit is not 0 or want_ack is + // set, start retransmissions + if (!isFromUs(p) && p->next_hop != NO_NEXT_HOP_PREFERENCE && (p->hop_limit > 0 || p->want_ack)) startRetransmission(packetPool.allocCopy(*p)); // start retransmission for relayed packet return Router::send(p); diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 5af5289996..589d3b74f4 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -29,7 +29,7 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd r.rxTimeMsec = millis(); r.next_hop = p->next_hop; r.relayed_by[0] = p->relay_node; - LOG_INFO("Add relayed_by 0x%x for id=0x%x", p->relay_node, r.id); + // LOG_INFO("Add relayed_by 0x%x for id=0x%x", p->relay_node, r.id); auto found = recentPackets.find(r); bool seenRecently = (found != recentPackets.end()); // found not equal to .end() means packet was seen recently @@ -56,7 +56,7 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && p->next_hop == NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && p->relay_node != 0 && wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) { - LOG_WARN("Fallback to flooding, consider unseen relay_node=0x%x", p->relay_node); + LOG_INFO("Fallback to flooding, consider unseen relay_node=0x%x", p->relay_node); seenRecently = false; } } @@ -159,4 +159,4 @@ void PacketHistory::removeRelayer(const uint8_t relayer, const uint32_t id, cons recentPackets.erase(found); recentPackets.insert(r); -} +} \ No newline at end of file From be73b099a73bf382e0d582c4f6f005dd9b133b12 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 8 Nov 2024 22:14:25 +0100 Subject: [PATCH 22/32] Fix cppcheck error --- src/mesh/PacketHistory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 589d3b74f4..5351821cce 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -112,6 +112,8 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N PacketRecord r; r.id = id; r.sender = sender; + r.rxTimeMsec = 0; + r.next_hop = 0; auto found = recentPackets.find(r); if (found == recentPackets.end()) { From 71a90b3b787ddcd4a9098c662d71a519e6e9e867 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Fri, 8 Nov 2024 22:22:43 +0100 Subject: [PATCH 23/32] Fix 'router' not in scope error --- src/mesh/PhoneAPI.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index edcc047366..e01b90435a 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -12,6 +12,7 @@ #include "PhoneAPI.h" #include "PowerFSM.h" #include "RadioInterface.h" +#include "Router.h" #include "TypeConversions.h" #include "main.h" #include "xmodem.h" @@ -636,4 +637,4 @@ int PhoneAPI::onNotify(uint32_t newValue) } return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one -} +} \ No newline at end of file From 93bcee3aabf59466b09fdb4a1f75d74685612236 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 9 Nov 2024 20:01:19 +0100 Subject: [PATCH 24/32] Fix another cppcheck error --- src/mesh/PacketHistory.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 5351821cce..da67b9add9 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -109,11 +109,7 @@ void PacketHistory::clearExpiredRecentPackets() * @return true if node was indeed a relayer, false if not */ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender) { - PacketRecord r; - r.id = id; - r.sender = sender; - r.rxTimeMsec = 0; - r.next_hop = 0; + PacketRecord r = {.sender = sender, .id = id, .rxTimeMsec = 0, .next_hop = 0}; auto found = recentPackets.find(r); if (found == recentPackets.end()) { @@ -138,9 +134,7 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, std::unordered_set Date: Mon, 11 Nov 2024 10:50:36 +0100 Subject: [PATCH 25/32] Check for hop_limit and also update next hop when `hop_start == hop_limit` on ACK Also check for broadcast in `getNextHop()` --- src/main.cpp | 2 +- src/mesh/NextHopRouter.cpp | 21 ++++++++++++--------- src/mesh/PacketHistory.cpp | 7 +++++-- src/mesh/RadioInterface.cpp | 8 ++++---- src/modules/Modules.cpp | 2 +- src/modules/NeighborInfoModule.cpp | 2 +- src/modules/NeighborInfoModule.h | 2 +- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 95e8ef8b38..be00696fe1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -653,7 +653,7 @@ void setup() // but we need to do this after main cpu init (esp32setup), because we need the random seed set nodeDB = new NodeDB; - // If we're taking on the repeater role, use flood router and turn off 3V3_S rail because peripherals are not needed + // If we're taking on the repeater role, use NextHopRouter and turn off 3V3_S rail because peripherals are not needed if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { router = new NextHopRouter(); #ifdef PIN_3V3_EN diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index df86866e96..781dd84cf2 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -54,14 +54,13 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast if (isAckorReply) { // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is // not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the destination - if (p->from != 0 && p->relay_node) { + if (p->from != 0) { meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from); if (origTx) { // Either relayer of ACK was also a relayer of the packet, or we were the relayer and the ACK came directly from // the destination if (wasRelayer(p->relay_node, p->decoded.request_id, p->to) || - (wasRelayer(ourRelayID, p->decoded.request_id, p->to) && - p->relay_node == nodeDB->getLastByteOfNodeNum(p->from))) { + (wasRelayer(ourRelayID, p->decoded.request_id, p->to) && p->hop_start != 0 && p->hop_start == p->hop_limit)) { if (origTx->next_hop != p->relay_node) { // Not already set LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply", p->from, p->relay_node); origTx->next_hop = p->relay_node; @@ -76,18 +75,18 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast } } - if (isRebroadcaster()) { - if (!isToUs(p) && !isFromUs(p)) { - if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == ourRelayID) { + if (!isToUs(p) && !isFromUs(p) && p->hop_limit > 0) { + if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == ourRelayID) { + if (isRebroadcaster()) { meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it LOG_INFO("Relaying received message coming from %x", p->relay_node); tosend->hop_limit--; // bump down the hop count NextHopRouter::send(tosend); - } // else don't relay + } else { + LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); + } } - } else { - LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } // handle the packet as normal Router::sniffReceived(p, c); @@ -99,6 +98,10 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast */ uint8_t NextHopRouter::getNextHop(NodeNum to, uint8_t relay_node) { + // When we're a repeater router->sniffReceived will call NextHopRouter directly without checking for broadcast + if (isBroadcast(to)) + return NO_NEXT_HOP_PREFERENCE; + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(to); if (node && node->next_hop) { // We are careful not to return the relay node as the next hop diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index da67b9add9..cb51fd9cf5 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -54,8 +54,8 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd // to handle it now uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && - p->next_hop == NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && p->relay_node != 0 && - wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) { + p->next_hop == NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && wasRelayer(p->relay_node, found) && + !wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) { LOG_INFO("Fallback to flooding, consider unseen relay_node=0x%x", p->relay_node); seenRecently = false; } @@ -109,6 +109,9 @@ void PacketHistory::clearExpiredRecentPackets() * @return true if node was indeed a relayer, false if not */ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender) { + if (relayer == 0) + return false; + PacketRecord r = {.sender = sender, .id = id, .rxTimeMsec = 0, .next_hop = 0}; auto found = recentPackets.find(r); diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index f209f4a027..af63576ee0 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -315,10 +315,6 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p) out += " encrypted"; } - if (p->next_hop != 0) - out += DEBUG_PORT.mt_sprintf(" nextHop=0x%x", p->next_hop); - if (p->relay_node != 0) - out += DEBUG_PORT.mt_sprintf(" relay=0x%x", p->relay_node); if (p->rx_time != 0) out += DEBUG_PORT.mt_sprintf(" rxtime=%u", p->rx_time); if (p->rx_snr != 0.0) @@ -329,6 +325,10 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p) out += DEBUG_PORT.mt_sprintf(" via MQTT"); if (p->hop_start != 0) out += DEBUG_PORT.mt_sprintf(" hopStart=%d", p->hop_start); + if (p->next_hop != 0) + out += DEBUG_PORT.mt_sprintf(" nextHop=0x%x", p->next_hop); + if (p->relay_node != 0) + out += DEBUG_PORT.mt_sprintf(" relay=0x%x", p->relay_node); if (p->priority != 0) out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority); diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 69211c76b8..ad3f0ace45 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -245,4 +245,4 @@ void setupModules() // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks routingModule = new RoutingModule(); -} +} \ No newline at end of file diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 63cbf58f36..e7160f929f 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -208,4 +208,4 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen neighbors.push_back(new_nbr); } return &neighbors.back(); -} +} \ No newline at end of file diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h index fb6a837854..aa76a21871 100644 --- a/src/modules/NeighborInfoModule.h +++ b/src/modules/NeighborInfoModule.h @@ -67,4 +67,4 @@ class NeighborInfoModule : public ProtobufModule, priva void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np); void printNodeDBNeighbors(); }; -extern NeighborInfoModule *neighborInfoModule; +extern NeighborInfoModule *neighborInfoModule; \ No newline at end of file From 42d17b33221442dbc97fd3071cf79823071916e2 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Mon, 11 Nov 2024 13:01:02 +0100 Subject: [PATCH 26/32] Formatting and correct NUM_RETRANSMISSIONS --- src/mesh/NextHopRouter.cpp | 3 ++- src/mesh/NextHopRouter.h | 22 +++++++++++++--------- src/mesh/PacketHistory.cpp | 12 ++++++------ src/mesh/ReliableRouter.cpp | 2 +- src/mesh/ReliableRouter.h | 2 -- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 781dd84cf2..940a453c9f 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -122,6 +122,7 @@ PendingPacket *NextHopRouter::findPendingPacket(GlobalPacketId key) } else return NULL; } + /** * Stop any retransmissions we are doing of the specified node/packet ID pair */ @@ -138,7 +139,7 @@ bool NextHopRouter::stopRetransmission(GlobalPacketId key) auto p = old->packet; /* Only when we already transmitted a packet via LoRa, we will cancel the packet in the Tx queue to avoid canceling a transmission if it was ACKed super fast via MQTT */ - if (old->numRetransmissions < NUM_RETRANSMISSIONS - 1) { + if (old->numRetransmissions < NUM_RELIABLE_RETX - 1) { // remove the 'original' (identified by originator and packet->id) from the txqueue and free it cancelSending(getFrom(p), p->id); // now free the pooled copy for retransmission too diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 376182e6e2..2ac0b7fa3d 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -49,13 +49,14 @@ class GlobalPacketIdHashFunction }; /* - Router which only relays if it is the next hop for a packet. - The next hop is set by the relay node 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. + Router for direct messages, 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 a previous successful delivery to the destination via flooding. + Namely, in the PacketHistory, we keep track of (up to 3) relayers of a packet. When the ACK is delivered back to us via a node + that also relayed the original packet, we use that node as next hop for the destination from then on. This makes sure that only + when there’s a two-way connection, we assign a next hop. Both the ReliableRouter and NextHopRouter will do retransmissions (the + NextHopRouter only 1 time). For the final retry, if no one actually relayed the packet, it will reset the next hop in order to + fall back to the FloodingRouter again. Note that thus also intermediate hops will do a single retransmission if the intended + next-hop didn’t relay, in order to fix changes in the middle of the route. */ class NextHopRouter : public FloodingRouter { @@ -85,7 +86,10 @@ class NextHopRouter : public FloodingRouter return min(d, r); } - constexpr static uint8_t NUM_RETRANSMISSIONS = 2; + // The number of retransmissions intermediate nodes will do (actually 1 less than this) + constexpr static uint8_t NUM_INTERMEDIATE_RETX = 2; + // The number of retransmissions the original sender will do + constexpr static uint8_t NUM_RELIABLE_RETX = 3; protected: /** @@ -115,7 +119,7 @@ class NextHopRouter : public FloodingRouter /** * Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting. */ - PendingPacket *startRetransmission(meshtastic_MeshPacket *p, uint8_t numReTx = NUM_RETRANSMISSIONS); + PendingPacket *startRetransmission(meshtastic_MeshPacket *p, uint8_t numReTx = NUM_INTERMEDIATE_RETX); /** * Stop any retransmissions we are doing of the specified node/packet ID pair diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index cb51fd9cf5..27df586d59 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -49,13 +49,13 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd } if (seenRecently) { - // If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, relayer relayed already before, it's - // a fallback to flooding. If we didn't already relay and the next-hop neither, consider it unseen because we might need - // to handle it now + // If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, and the relayer relayed already + // before, it's a fallback to flooding. If we didn't already relay and the next-hop neither, consider it unseen because we + // might need to handle it now uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); - if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && - p->next_hop == NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && wasRelayer(p->relay_node, found) && - !wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) { + if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && + p->next_hop == NO_NEXT_HOP_PREFERENCE && wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && + !wasRelayer(found->next_hop, found)) { LOG_INFO("Fallback to flooding, consider unseen relay_node=0x%x", p->relay_node); seenRecently = false; } diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index ff1c3e55d7..6e5c6231ba 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -23,7 +23,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) } auto copy = packetPool.allocCopy(*p); - startRetransmission(copy, this->NUM_RETRANSMISSIONS); + startRetransmission(copy, NUM_RELIABLE_RETX); } /* If we have pending retransmissions, add the airtime of this packet to it, because during that time we cannot receive an diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index b1ad99cd33..2cf10fb996 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -31,6 +31,4 @@ class ReliableRouter : public NextHopRouter * We hook this method so we can see packets before FloodingRouter says they should be discarded */ virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override; - - constexpr static uint8_t NUM_RETRANSMISSIONS = 3; }; \ No newline at end of file From b229abc2b41c1962829a985f335c6f389897f597 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 16 Nov 2024 13:42:32 +0100 Subject: [PATCH 27/32] Update protos --- src/mesh/generated/meshtastic/deviceonly.pb.h | 14 +++++++++----- src/mesh/generated/meshtastic/mesh.pb.h | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index dca5e5abb0..e52a914e02 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -90,6 +90,8 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; + /* Last byte of the node number of the node that should be used as the next hop to reach this node. */ + uint8_t next_hop; } meshtastic_NodeInfoLite; /* This message is never sent over the wire, but it is used for serializing DB @@ -153,12 +155,12 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0} #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}} #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_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0} #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}} #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} @@ -186,6 +188,7 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 +#define meshtastic_NodeInfoLite_next_hop_tag 12 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -231,7 +234,8 @@ X(a, STATIC, SINGULAR, UINT32, channel, 7) \ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ -X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) +X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 12) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -284,7 +288,7 @@ extern const pb_msgdesc_t meshtastic_ChannelFile_msg; /* meshtastic_DeviceState_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_ChannelFile_size #define meshtastic_ChannelFile_size 718 -#define meshtastic_NodeInfoLite_size 185 +#define meshtastic_NodeInfoLite_size 188 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 96 @@ -292,4 +296,4 @@ extern const pb_msgdesc_t meshtastic_ChannelFile_msg; } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index da7fa0d78e..275fc8e02f 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -1163,7 +1163,7 @@ extern "C" { #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 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, 0, 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, 0, 0, {0, {0}}, 0, 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, 0, false, 0, 0, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1188,7 +1188,7 @@ extern "C" { #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 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, 0, 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, 0, 0, {0, {0}}, 0, 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, 0, false, 0, 0, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1751,4 +1751,4 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif From 360637c25daaf72bbeb3c4afda1b843c098612fb Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 16 Nov 2024 16:31:31 +0100 Subject: [PATCH 28/32] Start retransmissions in NextHopRouter if ReliableRouter didn't do it --- src/mesh/NextHopRouter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 940a453c9f..aaa38c3590 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -20,9 +20,9 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) p->next_hop = getNextHop(p->to, p->relay_node); // set the next hop LOG_DEBUG("Setting next hop for packet with dest %x to %x", p->to, p->next_hop); - // If it's from us, ReliableRouter already handles retransmissions. If a next hop is set and hop limit is not 0 or want_ack is - // set, start retransmissions - if (!isFromUs(p) && p->next_hop != NO_NEXT_HOP_PREFERENCE && (p->hop_limit > 0 || p->want_ack)) + // If it's from us, ReliableRouter already handles retransmissions if want_ack is set. If a next hop is set and hop limit is + // not 0 or want_ack is set, start retransmissions + if ((!isFromUs(p) || !p->want_ack) && p->next_hop != NO_NEXT_HOP_PREFERENCE && (p->hop_limit > 0 || p->want_ack)) startRetransmission(packetPool.allocCopy(*p)); // start retransmission for relayed packet return Router::send(p); From bfc6a1940d85e17ea42c9509a0e26151850710ea Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 16 Nov 2024 16:32:24 +0100 Subject: [PATCH 29/32] Handle repeated/fallback to flooding packets properly First check if it's not still in the TxQueue --- src/mesh/FloodingRouter.cpp | 37 +++++++++++++------------ src/mesh/FloodingRouter.h | 8 ++++-- src/mesh/MeshPacketQueue.cpp | 13 +++++++++ src/mesh/MeshPacketQueue.h | 5 +++- src/mesh/NextHopRouter.cpp | 43 +++++++++++++++++++++-------- src/mesh/NextHopRouter.h | 4 +++ src/mesh/PacketHistory.cpp | 26 ++++++++--------- src/mesh/PacketHistory.h | 3 +- src/mesh/RadioInterface.h | 3 ++ src/mesh/RadioLibInterface.cpp | 6 ++++ src/mesh/RadioLibInterface.h | 3 ++ src/mesh/Router.cpp | 6 ++++ src/mesh/Router.h | 3 ++ src/platform/portduino/SimRadio.cpp | 8 +++++- src/platform/portduino/SimRadio.h | 3 ++ 15 files changed, 122 insertions(+), 49 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index dfc2ded22e..e177d3883a 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -22,23 +22,16 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { if (wasSeenRecently(p)) { // Note: this will also add a recent packet record - printPacket("Ignore dupe incoming msg", p); - rxDupe++; - if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && - config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { - // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! - if (Router::cancelSending(p->from, p->id)) - txRelayCanceled++; - } - /* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when - the ACK got lost, we will handle the packet again to make sure it gets an ACK to its packet. */ + the ACK got lost, we will handle the packet again to make sure it gets an implicit ACK. */ bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit; if (isRepeated) { LOG_DEBUG("Repeated reliable tx"); - if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) { - sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); - } + // Check if it's still in the Tx queue, if not, we have to relay it again + if (!findInTxQueue(p->from, p->id)) + perhapsRebroadcast(p); + } else { + perhapsCancelDupe(p); } return true; @@ -47,13 +40,25 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) return Router::shouldFilterReceived(p); } +void FloodingRouter::perhapsCancelDupe(const meshtastic_MeshPacket *p) +{ + printPacket("Ignore dupe incoming msg", p); + rxDupe++; + if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && + config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { + // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! + if (Router::cancelSending(p->from, p->id)) + txRelayCanceled++; + } +} + bool FloodingRouter::isRebroadcaster() { return config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE && config.device.rebroadcast_mode != meshtastic_Config_DeviceConfig_RebroadcastMode_NONE; } -bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) +void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) { if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { if (p->id != 0) { @@ -73,8 +78,6 @@ bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) // Note: we are careful to resend using the original senders node id // We are careful not to call our hooked version of send() - because we don't want to check this again Router::send(tosend); - - return true; } else { LOG_DEBUG("No rebroadcast: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } @@ -82,8 +85,6 @@ bool FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) LOG_DEBUG("Ignore 0 id broadcast"); } } - - return false; } void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 1b5c78c0f3..36c6ad8aa3 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -28,9 +28,8 @@ class FloodingRouter : public Router { private: - /** Check if we should rebroadcast this packet, and do so if needed - * @return true if rebroadcasted */ - bool perhapsRebroadcast(const meshtastic_MeshPacket *p); + /* Check if we should rebroadcast this packet, and do so if needed */ + void perhapsRebroadcast(const meshtastic_MeshPacket *p); public: /** @@ -60,6 +59,9 @@ class FloodingRouter : public Router */ virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override; + /* Call when receiving a duplicate packet to check whether we should cancel a packet in the Tx queue */ + void perhapsCancelDupe(const meshtastic_MeshPacket *p); + // Return true if we are a rebroadcaster bool isRebroadcaster(); }; \ No newline at end of file diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 99ef41c1e4..58aa8f1282 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -107,6 +107,19 @@ meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id) return NULL; } +/* Attempt to find a packet from this queue. Return true if it was found. */ +bool MeshPacketQueue::find(NodeNum from, PacketId id) +{ + for (auto it = queue.begin(); it != queue.end(); it++) { + auto p = (*it); + if (getFrom(p) == from && p->id == id) { + return true; + } + } + + return false; +} + /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p) { diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index 3c28fc5ce7..00c15e4930 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -37,4 +37,7 @@ class MeshPacketQueue /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ meshtastic_MeshPacket *remove(NodeNum from, PacketId id); -}; + + /* Attempt to find a packet from this queue. Return true if it was found. */ + bool find(NodeNum from, PacketId id); +}; \ No newline at end of file diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index aaa38c3590..a7dff63f63 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -30,15 +30,25 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { - if (wasSeenRecently(p)) { // Note: this will return false for a fallback to flooding - printPacket("Already seen, try stop re-Tx and cancel sending", p); - rxDupe++; + bool wasFallback = false; + if (wasSeenRecently(p, true, &wasFallback)) { // Note: this will also add a recent packet record stopRetransmission(p->from, p->id); - if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && - config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { - // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! - if (Router::cancelSending(p->from, p->id)) - txRelayCanceled++; + + // If it was a fallback to flooding, try to relay again + if (wasFallback) { + LOG_INFO("Fallback to flooding from relay_node=0x%x", p->relay_node); + // Check if it's still in the Tx queue, if not, we have to relay it again + if (!findInTxQueue(p->from, p->id)) + perhapsRelay(p); + } else { + bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit; + // If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again + if (isRepeated) { + if (!findInTxQueue(p->from, p->id) && !perhapsRelay(p) && isToUs(p) && p->want_ack) + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); + } else { + perhapsCancelDupe(p); // If it's a dupe, cancel relay + } } return true; } @@ -75,21 +85,32 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast } } + perhapsRelay(p); + + // handle the packet as normal + Router::sniffReceived(p, c); +} + +/* Check if we should be relaying this packet if so, do so. */ +bool NextHopRouter::perhapsRelay(const meshtastic_MeshPacket *p) +{ if (!isToUs(p) && !isFromUs(p) && p->hop_limit > 0) { - if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == ourRelayID) { + if (p->next_hop == NO_NEXT_HOP_PREFERENCE || p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum())) { if (isRebroadcaster()) { meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it LOG_INFO("Relaying received message coming from %x", p->relay_node); tosend->hop_limit--; // bump down the hop count NextHopRouter::send(tosend); + + return true; } else { LOG_DEBUG("Not rebroadcasting: Role = CLIENT_MUTE or Rebroadcast Mode = NONE"); } } } - // handle the packet as normal - Router::sniffReceived(p, c); + + return false; } /** diff --git a/src/mesh/NextHopRouter.h b/src/mesh/NextHopRouter.h index 2ac0b7fa3d..6c2764aff7 100644 --- a/src/mesh/NextHopRouter.h +++ b/src/mesh/NextHopRouter.h @@ -144,4 +144,8 @@ class NextHopRouter : public FloodingRouter * @return the node number of the next hop, 0 if no preference (fallback to FloodingRouter) */ uint8_t getNextHop(NodeNum to, uint8_t relay_node); + + /** Check if we should be relaying this packet if so, do so. + * @return true if we did relay */ + bool perhapsRelay(const meshtastic_MeshPacket *p); }; \ No newline at end of file diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index c663584c26..73c3d56f14 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -16,7 +16,7 @@ PacketHistory::PacketHistory() /** * Update recentBroadcasts and return true if we have already seen this packet */ -bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate) +bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate, bool *wasFallback) { if (p->id == 0) { LOG_DEBUG("Ignore message with zero id"); @@ -41,21 +41,19 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd seenRecently = false; } - if (seenRecently) { - // If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, and the relayer relayed already - // before, it's a fallback to flooding. If we didn't already relay and the next-hop neither, consider it unseen because we - // might need to handle it now - uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); - if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && - p->next_hop == NO_NEXT_HOP_PREFERENCE && wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && - !wasRelayer(found->next_hop, found)) { - LOG_INFO("Fallback to flooding, consider unseen relay_node=0x%x", p->relay_node); - seenRecently = false; - } - } - if (seenRecently) { LOG_DEBUG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x", p->from, p->to, p->id); + if (wasFallback) { + // If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, and the relayer relayed already + // before, it's a fallback to flooding. If we didn't already relay and the next-hop neither, we might need to handle + // it now. + uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); + if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && + found->next_hop != ourRelayID && p->next_hop == NO_NEXT_HOP_PREFERENCE && wasRelayer(p->relay_node, found) && + !wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) { + *wasFallback = true; + } + } } if (withUpdate) { diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index aae5ebff17..15c071da78 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -45,8 +45,9 @@ class PacketHistory * Update recentBroadcasts and return true if we have already seen this packet * * @param withUpdate if true and not found we add an entry to recentPackets + * @param wasFallback if not nullptr, packet will be checked for fallback to flooding and value will be set to true if so */ - bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true); + bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true, bool *wasFallback = nullptr); /* Check if a certain node was a relayer of a packet in the history given an ID and sender * @return true if node was indeed a relayer, false if not */ diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 8d3c19c42d..1e0adb7a7e 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -155,6 +155,9 @@ class RadioInterface /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ virtual bool cancelSending(NodeNum from, PacketId id) { return false; } + /** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ + virtual bool findInTxQueue(NodeNum from, PacketId id) { return false; } + // methods from radiohead /// Initialise the Driver transport hardware and software. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 2f6ffc2a04..eece61ca54 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -246,6 +246,12 @@ bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) return result; } +/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ +bool RadioLibInterface::findInTxQueue(NodeNum from, PacketId id) +{ + return txQueue.find(from, id); +} + /** radio helper thread callback. We never immediately transmit after any operation (either Rx or Tx). Instead we should wait a random multiple of 'slotTimes' (see definition in RadioInterface.h) taken from a contention window (CW) to lower the chance of collision. diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index a5c2e30ddc..f9dfbfd704 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -142,6 +142,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ virtual bool cancelSending(NodeNum from, PacketId id) override; + /** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ + virtual bool findInTxQueue(NodeNum from, PacketId id) override; + private: /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually * doing the transmit */ diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index cc33bd0a27..93913bda77 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -299,6 +299,12 @@ bool Router::cancelSending(NodeNum from, PacketId id) return false; } +/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ +bool Router::findInTxQueue(NodeNum from, PacketId id) +{ + return iface->findInTxQueue(from, id); +} + /** * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 14ce4810b6..e74f7c2fdf 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -51,6 +51,9 @@ class Router : protected concurrency::OSThread, protected PacketHistory /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ bool cancelSending(NodeNum from, PacketId id); + /** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ + bool findInTxQueue(NodeNum from, PacketId id); + /** Allocate and return a meshpacket which defaults as send to broadcast from the current node. * The returned packet is guaranteed to have a unique packet ID already assigned */ diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index 0a77b6088c..845fce7fe5 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -133,6 +133,12 @@ bool SimRadio::cancelSending(NodeNum from, PacketId id) return result; } +/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ +bool SimRadio::findInTxQueue(NodeNum from, PacketId id) +{ + return txQueue.find(from, id); +} + void SimRadio::onNotify(uint32_t notification) { switch (notification) { @@ -265,4 +271,4 @@ int16_t SimRadio::readData(uint8_t *data, size_t len) } return state; -} +} \ No newline at end of file diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h index 1edb4963b4..886705a7e3 100644 --- a/src/platform/portduino/SimRadio.h +++ b/src/platform/portduino/SimRadio.h @@ -38,6 +38,9 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ virtual bool cancelSending(NodeNum from, PacketId id) override; + /** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ + virtual bool findInTxQueue(NodeNum from, PacketId id) override; + /** * Start waiting to receive a message * From 47116f65cdd9e33227f7fe0f02dbd5dff99222e6 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Mon, 18 Nov 2024 18:02:15 +0100 Subject: [PATCH 30/32] Guard against clients setting `next_hop`/`relay_node` --- src/mesh/MeshService.cpp | 4 +++- src/mesh/MeshTypes.h | 2 ++ src/mesh/RadioLibInterface.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 50a13da6a9..4b1a178cf6 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -190,7 +190,9 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p) return; } #endif - p.from = 0; // We don't let phones assign nodenums to their sent messages + p.from = 0; // We don't let clients assign nodenums to their sent messages + p.next_hop = NO_NEXT_HOP_PREFERENCE; // We don't let clients assign next_hop to their sent messages + p.relay_node = NO_RELAY_NODE; // We don't let clients assign relay_node to their sent messages if (p.id == 0) p.id = generatePacketId(); // If the phone didn't supply one, then pick one diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 0f14fe4cb8..3f25082f1d 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -42,6 +42,8 @@ enum RxSource { // For old firmware or when falling back to flooding, there is no next-hop preference #define NO_NEXT_HOP_PREFERENCE 0 +// For old firmware there is no relay node set +#define NO_RELAY_NODE 0 typedef int ErrorCode; diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index eece61ca54..433874523b 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -439,7 +439,7 @@ void RadioLibInterface::handleReceiveInterrupt() mp->via_mqtt = !!(radioBuffer.header.flags & PACKET_FLAGS_VIA_MQTT_MASK); // If hop_start is not set, next_hop and relay_node are invalid (firmware <2.3) mp->next_hop = mp->hop_start == 0 ? NO_NEXT_HOP_PREFERENCE : radioBuffer.header.next_hop; - mp->relay_node = mp->hop_start == 0 ? NO_NEXT_HOP_PREFERENCE : radioBuffer.header.relay_node; + mp->relay_node = mp->hop_start == 0 ? NO_RELAY_NODE : radioBuffer.header.relay_node; addReceiveMetadata(mp); From 0952c861ae4dee53df463169d7766d3fa1b8e0d5 Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Wed, 27 Nov 2024 19:44:19 +0100 Subject: [PATCH 31/32] Don't cancel relay if we were the assigned next-hop --- src/mesh/FloodingRouter.cpp | 5 +++-- src/mesh/NextHopRouter.cpp | 9 ++++++--- src/mesh/PacketHistory.cpp | 14 ++++++++++---- src/mesh/PacketHistory.h | 4 +++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index e177d3883a..6f47a81028 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -22,6 +22,8 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { if (wasSeenRecently(p)) { // Note: this will also add a recent packet record + printPacket("Ignore dupe incoming msg", p); + rxDupe++; /* If the original transmitter is doing retransmissions (hopStart equals hopLimit) for a reliable transmission, e.g., when the ACK got lost, we will handle the packet again to make sure it gets an implicit ACK. */ bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit; @@ -42,8 +44,6 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) void FloodingRouter::perhapsCancelDupe(const meshtastic_MeshPacket *p) { - printPacket("Ignore dupe incoming msg", p); - rxDupe++; if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! @@ -73,6 +73,7 @@ void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) tosend->hop_limit = 2; } #endif + tosend->next_hop = NO_NEXT_HOP_PREFERENCE; // this should already be the case, but just in case LOG_INFO("Rebroadcast received floodmsg"); // Note: we are careful to resend using the original senders node id diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index a7dff63f63..3c010eb6b5 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -31,7 +31,10 @@ ErrorCode NextHopRouter::send(meshtastic_MeshPacket *p) bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { bool wasFallback = false; - if (wasSeenRecently(p, true, &wasFallback)) { // Note: this will also add a recent packet record + bool weWereNextHop = false; + if (wasSeenRecently(p, true, &wasFallback, &weWereNextHop)) { // Note: this will also add a recent packet record + printPacket("Ignore dupe incoming msg", p); + rxDupe++; stopRetransmission(p->from, p->id); // If it was a fallback to flooding, try to relay again @@ -46,8 +49,8 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (isRepeated) { if (!findInTxQueue(p->from, p->id) && !perhapsRelay(p) && isToUs(p) && p->want_ack) sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); - } else { - perhapsCancelDupe(p); // If it's a dupe, cancel relay + } else if (!weWereNextHop) { + perhapsCancelDupe(p); // If it's a dupe, cancel relay if we were not explicitly asked to relay } } return true; diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 73c3d56f14..15fa9cdcd6 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -16,7 +16,7 @@ PacketHistory::PacketHistory() /** * Update recentBroadcasts and return true if we have already seen this packet */ -bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate, bool *wasFallback) +bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate, bool *wasFallback, bool *weWereNextHop) { if (p->id == 0) { LOG_DEBUG("Ignore message with zero id"); @@ -43,27 +43,33 @@ bool PacketHistory::wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpd if (seenRecently) { LOG_DEBUG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x", p->from, p->to, p->id); + uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); if (wasFallback) { // If it was seen with a next-hop not set to us and now it's NO_NEXT_HOP_PREFERENCE, and the relayer relayed already // before, it's a fallback to flooding. If we didn't already relay and the next-hop neither, we might need to handle // it now. - uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(nodeDB->getNodeNum()); if (found->sender != nodeDB->getNodeNum() && found->next_hop != NO_NEXT_HOP_PREFERENCE && found->next_hop != ourRelayID && p->next_hop == NO_NEXT_HOP_PREFERENCE && wasRelayer(p->relay_node, found) && !wasRelayer(ourRelayID, found) && !wasRelayer(found->next_hop, found)) { *wasFallback = true; } } + + // Check if we were the next hop for this packet + if (weWereNextHop) { + *weWereNextHop = found->next_hop == ourRelayID; + } } if (withUpdate) { - if (found != recentPackets.end()) { // delete existing to updated timestamp and next-hop/relayed_by (re-insert) + if (found != recentPackets.end()) { // delete existing to updated timestamp and relayed_by (re-insert) // Add the existing relayed_by to the new record for (uint8_t i = 0; i < NUM_RELAYERS - 1; i++) { if (found->relayed_by[i]) r.relayed_by[i + 1] = found->relayed_by[i]; } - recentPackets.erase(found); // as unsorted_set::iterator is const (can't update - so re-insert..) + r.next_hop = found->next_hop; // keep the original next_hop (such that we check whether we were originally asked) + recentPackets.erase(found); // as unsorted_set::iterator is const (can't update - so re-insert..) } recentPackets.insert(r); LOG_DEBUG("Add packet record fr=0x%x, id=0x%x", p->from, p->id); diff --git a/src/mesh/PacketHistory.h b/src/mesh/PacketHistory.h index 15c071da78..86d901d6ce 100644 --- a/src/mesh/PacketHistory.h +++ b/src/mesh/PacketHistory.h @@ -46,8 +46,10 @@ class PacketHistory * * @param withUpdate if true and not found we add an entry to recentPackets * @param wasFallback if not nullptr, packet will be checked for fallback to flooding and value will be set to true if so + * @param weWereNextHop if not nullptr, packet will be checked for us being the next hop and value will be set to true if so */ - bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true, bool *wasFallback = nullptr); + bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true, bool *wasFallback = nullptr, + bool *weWereNextHop = nullptr); /* Check if a certain node was a relayer of a packet in the history given an ID and sender * @return true if node was indeed a relayer, false if not */ From a3d9582b357abeb6e6c86f67dbeb7fe77fb3cdbb Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 11 Jan 2025 16:01:33 +0100 Subject: [PATCH 32/32] Replies (e.g. tapback emoji) are also a valid confirmation of receipt --- src/mesh/FloodingRouter.cpp | 3 ++- src/mesh/NextHopRouter.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 7caff87c66..142ada8064 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -95,7 +95,8 @@ void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) { - bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); + bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && + (p->decoded.request_id != 0 || p->decoded.reply_id != 0); if (isAckorReply && !isToUs(p) && !isBroadcast(p->to)) { // do not flood direct message that is ACKed or replied to LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast"); diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index 3c010eb6b5..f21974a2e9 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -63,7 +63,8 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast { NodeNum ourNodeNum = getNodeNum(); uint8_t ourRelayID = nodeDB->getLastByteOfNodeNum(ourNodeNum); - bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0); + bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && + (p->decoded.request_id != 0 || p->decoded.reply_id != 0); if (isAckorReply) { // Update next-hop for the original transmitter of this successful transmission to the relay node, but ONLY if "from" is // not 0 (means implicit ACK) and original packet was also relayed by this node, or we sent it directly to the destination