diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index ab6b7ca94..615a3be3d 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 646613914..e0d0cee1e 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 a8de540eb..fc8199c65 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 7929ba972..d37de0d83 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 0d052f482..8b1ff2f12 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 523d5ba11..e949e16a0 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 8ebc1a3e5..4414b1859 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 f11a9a542..5079aa5d8 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 f085b307b..7c34c5bc9 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