From ae6b7e7259c5caa4da3e90342264b0e67afe5346 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 10:45:03 +0800 Subject: [PATCH] multichannel code is done! (only basic testing completed though) --- docs/software/TODO.md | 8 +++++--- src/mesh/Channels.cpp | 15 +++++++++++---- src/mesh/Channels.h | 24 ++++++++++++----------- src/mesh/Router.cpp | 44 +++++++++++++++++++++---------------------- 4 files changed, 51 insertions(+), 40 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b30b58795..232ea2122 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -5,8 +5,8 @@ You probably don't care about this section - skip to the next one. 1.2 cleanup & multichannel support: * DONE call RouterPlugin for *all* packets - not just Router packets -* generate channel hash from the name of the channel+the psk (not just one or the other) -* send a hint that can be used to select which channel to try and hash against with each message +* DONE generate channel hash from the name of the channel+the psk (not just one or the other) +* DONE send a hint that can be used to select which channel to try and hash against with each message * DONE remove deprecated * DONE fix setchannel in phoneapi.cpp * DONE set mynodeinfo.max_channels @@ -15,7 +15,9 @@ You probably don't care about this section - skip to the next one. * DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware -* restrict settings operations to the admin channel +* test single channel +* test multi channel +* restrict gpio & serial & settings operations to the admin channel (unless local to the current node) * add gui in android app for setting region * make an alpha channel for the python API * "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index f3238b9c5..3e1ea3185 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -192,7 +192,7 @@ void Channels::setChannel(const Channel &c) // if this is the new primary, demote any existing roles if (c.role == Channel_Role_PRIMARY) - for (int i = 0; i < devicestate.channels_count; i++) + for (int i = 0; i < getNumChannels(); i++) if (devicestate.channels[i].role == Channel_Role_PRIMARY) devicestate.channels[i].role = Channel_Role_SECONDARY; @@ -271,11 +271,18 @@ const char *Channels::getPrimaryName() * * This method is called before decoding inbound packets * - * @return -1 if no suitable channel could be found, otherwise returns the channel index + * @return false if the channel hash or channel is invalid */ -int16_t Channels::setActiveByHash(ChannelHash channelHash) +bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash) { - // fixme cant work; + if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) { + DEBUG_MSG("Skipping channel %d due to invalid hash/index\n", chIndex); + return false; + } + else { + setCrypto(chIndex); + return true; + } } /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 4e70e2304..547b0a581 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -1,16 +1,17 @@ #pragma once +#include "CryptoEngine.h" +#include "NodeDB.h" #include "mesh-pb-constants.h" #include -#include "CryptoEngine.h" /** A channel number (index into the channel table) */ typedef uint8_t ChannelIndex; -/** A low quality hash of the channel PSK and the channel name. created by generateHash(chIndex) +/** A low quality hash of the channel PSK and the channel name. created by generateHash(chIndex) * Used as a hint to limit which PSKs are considered for packet decoding. -*/ + */ typedef uint8_t ChannelHash; /** The container/on device API for working with channels */ @@ -22,7 +23,7 @@ class Channels /** The channel index that was requested for sending/receving. Note: if this channel is a secondary channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled no sending or receiving will be allowed */ - ChannelIndex activeChannelIndex = 0; + ChannelIndex activeChannelIndex = 0; /// the precomputed hashes for each of our channels, or -1 for invalid int16_t hashes[MAX_NUM_CHANNELS]; @@ -43,6 +44,8 @@ class Channels /** The index of the primary channel */ ChannelIndex getPrimaryIndex() const { return primaryIndex; } + ChannelIndex getNumChannels() { return devicestate.channels_count; } + /** * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. @@ -72,9 +75,9 @@ class Channels * * This method is called before decoding inbound packets * - * @return -1 if no suitable channel could be found, otherwise returns the channel index + * @return false if the channel hash or channel is invalid */ - int16_t setActiveByHash(ChannelHash channelHash); + bool decryptForHash(ChannelIndex chIndex, ChannelHash channelHash); /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) * @@ -86,7 +89,7 @@ class Channels private: /** Given a channel index, change to use the crypto key specified by that index - * + * * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 */ int16_t setCrypto(ChannelIndex chIndex); @@ -96,7 +99,7 @@ class Channels /** Given a channel number, return the (0 to 255) hash for that channel * If no suitable channel could be found, return -1 - * + * * called by fixupChannel when a new channel is set */ int16_t generateHash(ChannelIndex channelNum); @@ -114,11 +117,10 @@ class Channels void initDefaultChannel(ChannelIndex chIndex); /** - * Return the key used for encrypting this channel (if channel is secondary and no key provided, use the primary channel's PSK) + * Return the key used for encrypting this channel (if channel is secondary and no key provided, use the primary channel's + * PSK) */ CryptoKey getKey(ChannelIndex chIndex); - - }; /// Singleton channel table diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 434bdde5d..50e4215b2 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -215,31 +215,31 @@ bool Router::perhapsDecode(MeshPacket *p) assert(p->which_payloadVariant == MeshPacket_encrypted_tag); - ChannelHash chHash = p->channel; - int16_t chIndex = channels.setActiveByHash(chHash); - if (chIndex < 0) { - DEBUG_MSG("No suitable channel found for decoding, hash was 0x%x!\n", chHash); - return false; - } else { - p->channel = chIndex; + // Try to find a channel that works with this hash + for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) { + // Try to use this hash/channel pair + if (channels.decryptForHash(chIndex, p->channel)) { + // Try to decrypt the packet if we can + static uint8_t bytes[MAX_RHPACKETLEN]; + memcpy(bytes, p->encrypted.bytes, + p->encrypted + .size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf + crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); - // Try to decrypt the packet if we can - static uint8_t bytes[MAX_RHPACKETLEN]; - memcpy(bytes, p->encrypted.bytes, - p->encrypted - .size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf - crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); - - // Take those raw bytes and convert them back into a well structured protobuf we can understand - if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { - DEBUG_MSG("Invalid protobufs in received mesh packet!\n"); - return false; - } else { - // parsing was successful - p->which_payloadVariant = MeshPacket_decoded_tag; - return true; + // Take those raw bytes and convert them back into a well structured protobuf we can understand + if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { + DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n"); + } else { + // parsing was successful + p->channel = chIndex; // change to store the index instead of the hash + p->which_payloadVariant = MeshPacket_decoded_tag; + return true; + } } } + + DEBUG_MSG("No suitable channel found for decoding, hash was 0x%x!\n", p->channel); + return false; } NodeNum Router::getNodeNum()