From 4a7b1935d5175e4718b8e42e6d04f21c4fd64674 Mon Sep 17 00:00:00 2001 From: DeFiDude <59237470+DeFiDude@users.noreply.github.com> Date: Sat, 21 Mar 2026 14:00:12 -0600 Subject: [PATCH] Workaround LoRa link delivery truncation for large LXMF messages Link delivery adds ~64 bytes of overhead (dest_hash + Token IV/HMAC/padding) which can push encrypted payloads past the 255-byte LoRa MTU. SX1262::write() silently truncates, corrupting the HMAC and failing decryption on the receiver. Band-aid: cap link delivery plaintext at 180 bytes, falling back to opportunistic delivery for larger messages. Long-term fix needed: negotiate link MTU based on interface HW_MTU, or implement Resource-based multi-packet transfer for oversized payloads. --- src/radio/SX1262.cpp | 3 +++ src/reticulum/LXMFManager.cpp | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/radio/SX1262.cpp b/src/radio/SX1262.cpp index d99cceb..59a8c9e 100644 --- a/src/radio/SX1262.cpp +++ b/src/radio/SX1262.cpp @@ -367,6 +367,9 @@ size_t SX1262::write(uint8_t byte) { return write(&byte, 1); } size_t SX1262::write(const uint8_t* buffer, size_t size) { if ((_payloadLength + size) > MAX_PACKET_SIZE) { + Serial.printf("[SX1262] WARNING: write() truncating %d->%d bytes (payload=%d max=%d)\n", + (int)size, (int)(MAX_PACKET_SIZE - _payloadLength), + (int)_payloadLength, (int)MAX_PACKET_SIZE); size = MAX_PACKET_SIZE - _payloadLength; } writeBuffer(buffer, size); diff --git a/src/reticulum/LXMFManager.cpp b/src/reticulum/LXMFManager.cpp index 3d7f9d6..7e41256 100644 --- a/src/reticulum/LXMFManager.cpp +++ b/src/reticulum/LXMFManager.cpp @@ -152,12 +152,22 @@ bool LXMFManager::sendDirect(LXMFMessage& msg) { linkPayload.insert(linkPayload.end(), msg.destHash.data(), msg.destHash.data() + 16); linkPayload.insert(linkPayload.end(), payload.begin(), payload.end()); RNS::Bytes linkBytes(linkPayload.data(), linkPayload.size()); - if (linkBytes.size() <= RNS::Type::Reticulum::MDU) { + // Token encryption adds ~48 bytes (IV:16 + HMAC:32 + AES padding). + // LoRa packets are max 255 bytes (1 header + 19 Reticulum H1 + encrypted). + // If the plaintext is too large, Token output exceeds LoRa MTU and + // SX1262::write() silently truncates, corrupting the HMAC. + // Cap link delivery to 180 bytes to stay safely under the limit. + // Larger messages fall through to opportunistic delivery. + static constexpr size_t LORA_SAFE_LINK_PAYLOAD = 180; + if (linkBytes.size() <= LORA_SAFE_LINK_PAYLOAD) { Serial.printf("[LXMF] sending via link: %d bytes to %s\n", (int)linkBytes.size(), msg.destHash.toHex().substr(0, 8).c_str()); RNS::Packet packet(_outLink, linkBytes); RNS::PacketReceipt receipt = packet.send(); if (receipt) { sent = true; } + } else { + Serial.printf("[LXMF] link payload too large for LoRa (%d > %d), using opportunistic\n", + (int)linkBytes.size(), (int)LORA_SAFE_LINK_PAYLOAD); } }