From cdd996248cfaf9346b4d133e4e42dc137de80318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 27 Jul 2026 21:57:39 +0200 Subject: [PATCH] Release the opaque relay copy the interface declines to send (#11262) relayOpaquePacket() allocates a copy and returns Router::send(relay) == ERRNO_OK, discarding ERRNO_SHOULD_RELEASE. The interface returns that for NODENUM_BROADCAST_NO_LORA, so the copy is never freed and one pool slot leaks per frame. The opaque path is reached for packets on a channel we have no key for, so no key or PSK is needed: a frame with an unknown channel hash, to=NODENUM_BROADCAST_NO_LORA, a nonzero id and hop_limit>0 leaks a slot, and roughly MAX_PACKETS of them exhaust the pool until reboot. #11087 fixed this pattern in perhapsRebroadcast and the retransmission paths but did not cover relayOpaquePacket, which was added separately with the opaque relay path. --- src/mesh/NextHopRouter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mesh/NextHopRouter.cpp b/src/mesh/NextHopRouter.cpp index f1ed831f8..029648e2d 100644 --- a/src/mesh/NextHopRouter.cpp +++ b/src/mesh/NextHopRouter.cpp @@ -27,7 +27,12 @@ bool NextHopRouter::relayOpaquePacket(const meshtastic_MeshPacket *p) return false; relay->hop_limit--; relay->relay_node = nodeDB->getLastByteOfNodeNum(getNodeNum()); - return Router::send(relay) == ERRNO_OK; + // The interface declines some packets (NODENUM_BROADCAST_NO_LORA) with ERRNO_SHOULD_RELEASE, + // which leaves the copy ours to free. Dropping it here would leak a pool slot per opaque frame. + ErrorCode res = Router::send(relay); + if (res == ERRNO_SHOULD_RELEASE) + packetPool.release(relay); + return res == ERRNO_OK; } PendingPacket::PendingPacket(meshtastic_MeshPacket *p, uint8_t numRetransmissions)