diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 4dcd94e3b9..f3dfae88ed 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -459,4 +459,15 @@ bool Channels::setDefaultPresetCryptoForHash(ChannelHash channelHash) int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) { return setCrypto(channelIndex); +} + +int8_t Channels::getIndexByHash(ChannelHash channelHash) +{ + // Iterate through all channels to find the one with matching hash + for (ChannelIndex i = 0; i < getNumChannels(); i++) { + if (getHash(i) == channelHash) { + return i; + } + } + return -1; // Hash not found } \ No newline at end of file diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index b53f552fa5..499401c5ca 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -96,6 +96,9 @@ class Channels bool setDefaultPresetCryptoForHash(ChannelHash channelHash); + /** Return the channel index for the specified channel hash, or -1 for not found */ + int8_t getIndexByHash(ChannelHash channelHash); + private: /** Given a channel index, change to use the crypto key specified by that index * @@ -103,9 +106,6 @@ class Channels */ int16_t setCrypto(ChannelIndex chIndex); - /** Return the channel index for the specified channel hash, or -1 for not found */ - int8_t getIndexByHash(ChannelHash channelHash); - /** Given a channel number, return the (0 to 255) hash for that channel * If no suitable channel could be found, return -1 * diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 60637cbd18..41ae566711 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -356,13 +356,55 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) { mqtt->onSend(*p, *p_decoded, chIndex); } +#endif +#if HAS_UDP_MULTICAST + if (udpHandler && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) { + // We must have at least one channel setup for with uplink_enabled + bool uplinkEnabled = false; + for (int i = 0; i <= 7; i++) { + if (channels.getByIndex(i).settings.uplink_enabled) + uplinkEnabled = true; + } + if (uplinkEnabled) { + udpHandler->onSend(const_cast(p), chIndex); + } + } #endif packetPool.release(p_decoded); } - #if HAS_UDP_MULTICAST - if (udpHandler && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) { - udpHandler->onSend(const_cast(p)); + // For packets that are already encrypted, we need to determine the channel from packet info + else if (udpHandler && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST && + isFromUs(p)) { + // Check if any channel has uplink enabled (for PKI support) + bool uplinkEnabled = false; + for (int i = 0; i <= 7; i++) { + if (channels.getByIndex(i).settings.uplink_enabled) { + uplinkEnabled = true; + break; + } + } + if (uplinkEnabled) { + ChannelIndex chIndex = 0; // Default to primary channel + + // For PKI encrypted packets, use default channel if at least one channel has uplink + if (p->pki_encrypted) { + for (int i = 0; i <= 7; i++) { + if (channels.getByIndex(i).settings.uplink_enabled) { + chIndex = i; + break; + } + } + udpHandler->onSend(const_cast(p), chIndex); + } else { + // For regular channel PSK encrypted packets, try to find the channel by hash + int8_t foundIndex = channels.getIndexByHash(p->channel); + if (foundIndex >= 0) { + chIndex = foundIndex; + udpHandler->onSend(const_cast(p), chIndex); + } + } + } } #endif @@ -480,6 +522,35 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p) } } +#if HAS_UDP_MULTICAST + // Fallback: for UDP multicast, try default preset names with default PSK if normal channel match failed + if (!decrypted && p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MULTICAST_UDP) { + if (channels.setDefaultPresetCryptoForHash(p->channel)) { + memcpy(bytes, p->encrypted.bytes, rawSize); + crypto->decrypt(p->from, p->id, rawSize, bytes); + + meshtastic_Data decodedtmp; + memset(&decodedtmp, 0, sizeof(decodedtmp)); + if (pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &decodedtmp) && + decodedtmp.portnum != meshtastic_PortNum_UNKNOWN_APP) { + p->decoded = decodedtmp; + p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; + // Map to our local default channel index (name+PSK default), not necessarily primary + ChannelIndex defaultIndex = channels.getPrimaryIndex(); + for (ChannelIndex i = 0; i < channels.getNumChannels(); ++i) { + if (channels.isDefaultChannel(i)) { + defaultIndex = i; + break; + } + } + chIndex = defaultIndex; + decrypted = true; + } else { + LOG_WARN("UDP fallback decode attempted but failed for hash 0x%x", p->channel); + } + } + } +#endif if (decrypted) { // parsing was successful p->channel = chIndex; // change to store the index instead of the hash diff --git a/src/mesh/udp/UdpMulticastHandler.h b/src/mesh/udp/UdpMulticastHandler.h index 2df8686a31..b04785f302 100644 --- a/src/mesh/udp/UdpMulticastHandler.h +++ b/src/mesh/udp/UdpMulticastHandler.h @@ -2,6 +2,7 @@ #if HAS_UDP_MULTICAST #include "configuration.h" #include "main.h" +#include "mesh/Channels.h" #include "mesh/Router.h" #if HAS_ETHERNET && defined(ARCH_NRF52) @@ -53,6 +54,20 @@ class UdpMulticastHandler final LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength); bool isPacketDecoded = pb_decode_from_bytes(packet.data(), packetLength, &meshtastic_MeshPacket_msg, &mp); if (isPacketDecoded && router && mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag) { + // Convert channel hash to index for downlink check + int8_t chIndex = channels.getIndexByHash(mp.channel); + if (chIndex < 0) { + LOG_DEBUG("UDP received packet with unknown channel hash 0x%x", mp.channel); + return; + } + + // Check if downlink is enabled for this channel + auto &ch = channels.getByIndex(chIndex); + if (!ch.settings.downlink_enabled) { + LOG_DEBUG("UDP downlink disabled for channel %d", chIndex); + return; + } + mp.transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MULTICAST_UDP; mp.pki_encrypted = false; mp.public_key.size = 0; @@ -65,11 +80,17 @@ class UdpMulticastHandler final } } - bool onSend(const meshtastic_MeshPacket *mp) + bool onSend(const meshtastic_MeshPacket *mp, ChannelIndex chIndex) { if (!mp || !udp) { return false; } + // Check if uplink is enabled for this specific channel + auto &ch = channels.getByIndex(chIndex); + if (!ch.settings.uplink_enabled) { + LOG_DEBUG("UDP uplink disabled for channel %d", chIndex); + return false; + } #if defined(ARCH_NRF52) if (!isEthernetAvailable()) { return false;