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.
This commit is contained in:
Thomas Göttgens
2026-07-27 15:57:39 -04:00
committed by GitHub
co-authored by GitHub
parent 134fe5ec3e
commit cdd996248c
+6 -1
View File
@@ -27,7 +27,12 @@ bool NextHopRouter::relayOpaquePacket(const meshtastic_MeshPacket *p)
return false; return false;
relay->hop_limit--; relay->hop_limit--;
relay->relay_node = nodeDB->getLastByteOfNodeNum(getNodeNum()); 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) PendingPacket::PendingPacket(meshtastic_MeshPacket *p, uint8_t numRetransmissions)