mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-26 09:59:01 +00:00
begin multichannel hash impl
This commit is contained in:
parent
923ecc9d8a
commit
94cd96cfde
2
proto
2
proto
@ -1 +1 @@
|
||||
Subproject commit 6421b29ef45dbd34d7c6c43f4be48a7906e66ad9
|
||||
Subproject commit f6ff4cc0c98b201342c32776eeeb9ace83b450dd
|
@ -10,12 +10,20 @@ static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0
|
||||
|
||||
Channels channels;
|
||||
|
||||
uint8_t xorHash(uint8_t *p, size_t len)
|
||||
{
|
||||
uint8_t code = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
code ^= p[i];
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a channel, fixing any errors as needed
|
||||
*/
|
||||
Channel &Channels::fixupChannel(ChannelIndex chIndex)
|
||||
{
|
||||
auto ch = getByIndex(chIndex);
|
||||
Channel &ch = getByIndex(chIndex);
|
||||
|
||||
ch.index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later)
|
||||
|
||||
@ -31,14 +39,16 @@ Channel &Channels::fixupChannel(ChannelIndex chIndex)
|
||||
if (strcmp(channelSettings.name, "Default") == 0)
|
||||
*channelSettings.name = '\0';
|
||||
|
||||
// Convert any old usage of the defaultpsk into our new short representation.
|
||||
/* Convert any old usage of the defaultpsk into our new short representation.
|
||||
if (channelSettings.psk.size == sizeof(defaultpsk) &&
|
||||
memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) {
|
||||
*channelSettings.psk.bytes = 1;
|
||||
channelSettings.psk.size = 1;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
hashes[chIndex] = generateHash(chIndex);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
@ -47,7 +57,7 @@ Channel &Channels::fixupChannel(ChannelIndex chIndex)
|
||||
*/
|
||||
void Channels::initDefaultChannel(ChannelIndex chIndex)
|
||||
{
|
||||
auto ch = getByIndex(chIndex);
|
||||
Channel &ch = getByIndex(chIndex);
|
||||
ChannelSettings &channelSettings = ch.settings;
|
||||
|
||||
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
|
||||
@ -69,7 +79,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
|
||||
*/
|
||||
void Channels::setCrypto(ChannelIndex chIndex)
|
||||
{
|
||||
auto ch = getByIndex(chIndex);
|
||||
Channel &ch = getByIndex(chIndex);
|
||||
ChannelSettings &channelSettings = ch.settings;
|
||||
assert(ch.has_settings);
|
||||
|
||||
@ -124,7 +134,7 @@ void Channels::onConfigChanged()
|
||||
{
|
||||
// Make sure the phone hasn't mucked anything up
|
||||
for (int i = 0; i < devicestate.channels_count; i++) {
|
||||
auto ch = fixupChannel(i);
|
||||
Channel &ch = fixupChannel(i);
|
||||
|
||||
if (ch.role == Channel_Role_PRIMARY)
|
||||
primaryIndex = i;
|
||||
@ -211,9 +221,7 @@ const char *Channels::getPrimaryName()
|
||||
auto channelSettings = getPrimary();
|
||||
if (channelSettings.psk.size != 1) {
|
||||
// We have a standard PSK, so generate a letter based hash.
|
||||
uint8_t code = 0;
|
||||
for (int i = 0; i < activePSKSize; i++)
|
||||
code ^= activePSK[i];
|
||||
uint8_t code = xorHash(activePSK, activePSKSize);
|
||||
|
||||
suffix = 'A' + (code % 26);
|
||||
} else {
|
||||
@ -222,4 +230,25 @@ const char *Channels::getPrimaryName()
|
||||
|
||||
snprintf(buf, sizeof(buf), "#%s-%c", channelSettings.name, suffix);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured)
|
||||
*
|
||||
* This method is called before decoding inbound packets
|
||||
*
|
||||
* @return -1 if no suitable channel could be found, otherwise returns the channel index
|
||||
*/
|
||||
int16_t Channels::setActiveByHash(ChannelHash channelHash) {}
|
||||
|
||||
/** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured)
|
||||
*
|
||||
* This method is called before encoding outbound packets
|
||||
*
|
||||
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
|
||||
*/
|
||||
int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) {}
|
||||
|
||||
/** Given a channel number, return the (0 to 255) hash for that channel
|
||||
* If no suitable channel could be found, return -1
|
||||
*/
|
||||
ChannelHash Channels::generateHash(ChannelIndex channelNum) {}
|
@ -3,7 +3,13 @@
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <Arduino.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)
|
||||
* 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 */
|
||||
@ -21,6 +27,9 @@ class Channels
|
||||
uint8_t activePSK[32];
|
||||
uint8_t activePSKSize = 0;
|
||||
|
||||
/// the precomputed hashes for each of our channels
|
||||
ChannelHash hashes[MAX_NUM_CHANNELS];
|
||||
|
||||
public:
|
||||
const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
|
||||
|
||||
@ -66,18 +75,21 @@ class Channels
|
||||
*
|
||||
* This method is called before decoding inbound packets
|
||||
*
|
||||
* @return false if no suitable channel could be found.
|
||||
* @return -1 if no suitable channel could be found, otherwise returns the channel index
|
||||
*/
|
||||
bool setActiveByHash(ChannelHash channelHash);
|
||||
int16_t setActiveByHash(ChannelHash channelHash);
|
||||
|
||||
/** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured)
|
||||
*
|
||||
* This method is called before encoding inbound packets
|
||||
* This method is called before encoding outbound packets
|
||||
*
|
||||
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
|
||||
*/
|
||||
int16_t setActiveByIndex(ChannelIndex channelIndex);
|
||||
|
||||
/** return the channel hash we are currently using for sending */
|
||||
ChannelHash getActiveHash();
|
||||
|
||||
private:
|
||||
/** Given a channel index, change to use the crypto key specified by that index
|
||||
*/
|
||||
@ -89,7 +101,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
|
||||
*/
|
||||
int16_t getHash(ChannelIndex channelNum);
|
||||
ChannelHash generateHash(ChannelIndex channelNum);
|
||||
|
||||
/**
|
||||
* Validate a channel, fixing any errors as needed
|
||||
|
@ -14,6 +14,8 @@ typedef uint32_t PacketId; // A packet sequence number
|
||||
#define ERRNO_NO_INTERFACES 33
|
||||
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
|
||||
#define ERRNO_DISABLED 34 // the itnerface is disabled
|
||||
#define ERRNO_TOO_LARGE 35
|
||||
#define ERRNO_NO_CHANNEL 36
|
||||
|
||||
/**
|
||||
* the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket.
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <assert.h>
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
#include "Channels.h"
|
||||
|
||||
#define RDEF(name, freq, spacing, num_ch, power_limit) \
|
||||
{ \
|
||||
@ -157,7 +158,7 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
||||
|
||||
RadioInterface::RadioInterface()
|
||||
{
|
||||
assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
|
||||
assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
|
||||
|
||||
// Can't print strings this early - serial not setup yet
|
||||
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
|
||||
@ -350,6 +351,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
|
||||
h->from = p->from;
|
||||
h->to = p->to;
|
||||
h->id = p->id;
|
||||
h->channel = p->channel;
|
||||
assert(p->hop_limit <= HOP_MAX);
|
||||
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0);
|
||||
|
||||
|
@ -29,6 +29,9 @@ typedef struct {
|
||||
* The bottom three bits of flags are use to store hop_limit when sent over the wire.
|
||||
**/
|
||||
uint8_t flags;
|
||||
|
||||
/** The channel hash - used as a hint for the decoder to limit which channels we consider */
|
||||
uint8_t channel;
|
||||
} PacketHeader;
|
||||
|
||||
/**
|
||||
|
@ -274,6 +274,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
mp->from = h->from;
|
||||
mp->to = h->to;
|
||||
mp->id = h->id;
|
||||
mp->channel = h->id;
|
||||
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
|
||||
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
|
||||
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include "Router.h"
|
||||
#include "Channels.h"
|
||||
#include "CryptoEngine.h"
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
#include "configuration.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <NodeDB.h>
|
||||
#include "plugins/RoutingPlugin.h"
|
||||
|
||||
/**
|
||||
@ -107,7 +108,12 @@ void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom)
|
||||
routingPlugin->sendAckNak(err, to, idFrom);
|
||||
}
|
||||
|
||||
|
||||
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err);
|
||||
sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id);
|
||||
packetPool.release(p);
|
||||
}
|
||||
|
||||
ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
{
|
||||
@ -118,11 +124,7 @@ ErrorCode Router::sendLocal(MeshPacket *p)
|
||||
return ERRNO_OK;
|
||||
} else if (!iface) {
|
||||
// We must be sending to remote nodes also, fail if no interface found
|
||||
|
||||
// ERROR! no radio found, report failure back to the client and drop the packet
|
||||
DEBUG_MSG("Error: No interface, returning NAK and dropping packet.\n");
|
||||
sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id);
|
||||
packetPool.release(p);
|
||||
abortSendAndNak(Routing_Error_NO_INTERFACE, p);
|
||||
|
||||
return ERRNO_NO_INTERFACES;
|
||||
} else {
|
||||
@ -146,7 +148,8 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
|
||||
|
||||
// PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0;
|
||||
// assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert
|
||||
// assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with
|
||||
// assert
|
||||
|
||||
// Never set the want_ack flag on broadcast packets sent over the air.
|
||||
if (p->to == NODENUM_BROADCAST)
|
||||
@ -163,7 +166,20 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
|
||||
assert(numbytes <= MAX_RHPACKETLEN);
|
||||
if (numbytes > MAX_RHPACKETLEN) {
|
||||
abortSendAndNak(Routing_Error_TOO_LARGE, p);
|
||||
return ERRNO_TOO_LARGE;
|
||||
}
|
||||
|
||||
auto hash = channels.setActiveByIndex(p->channel);
|
||||
if (hash < 0) {
|
||||
// No suitable channel could be found for sending
|
||||
abortSendAndNak(Routing_Error_NO_CHANNEL, p);
|
||||
return ERRNO_NO_CHANNEL;
|
||||
}
|
||||
|
||||
// Now that we are encrypting the packet channel should be the hash (no longer the index)
|
||||
p->channel = hash;
|
||||
crypto->encrypt(p->from, p->id, numbytes, bytes);
|
||||
|
||||
// Copy back into the packet and set the variant type
|
||||
@ -173,23 +189,15 @@ ErrorCode Router::send(MeshPacket *p)
|
||||
}
|
||||
|
||||
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)
|
||||
// if (iface) {
|
||||
// DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
return iface->send(p);
|
||||
/* } else {
|
||||
DEBUG_MSG("Dropping packet - no interfaces - fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
packetPool.release(p);
|
||||
return ERRNO_NO_INTERFACES;
|
||||
} */
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
bool Router::cancelSending(NodeNum from, PacketId id) {
|
||||
bool Router::cancelSending(NodeNum from, PacketId id)
|
||||
{
|
||||
return iface ? iface->cancelSending(from, id) : false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
|
||||
* update routing tables etc... based on what we overhear (even for messages not destined to our node)
|
||||
@ -207,22 +215,30 @@ bool Router::perhapsDecode(MeshPacket *p)
|
||||
|
||||
assert(p->which_payloadVariant == MeshPacket_encrypted_tag);
|
||||
|
||||
// FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without
|
||||
// being able to decrypt their data.
|
||||
// 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");
|
||||
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 {
|
||||
// parsing was successful
|
||||
p->which_payloadVariant = MeshPacket_decoded_tag;
|
||||
return true;
|
||||
p->channel = chIndex;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +260,7 @@ void Router::handleReceived(MeshPacket *p)
|
||||
if (perhapsDecode(p)) {
|
||||
// parsing was successful, queue for our recipient
|
||||
|
||||
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
|
||||
// call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api
|
||||
// sniffReceived(p);
|
||||
MeshPlugin::callPlugins(*p);
|
||||
}
|
||||
|
@ -123,6 +123,9 @@ class Router : protected concurrency::OSThread
|
||||
* Note: this method will free the provided packet.
|
||||
*/
|
||||
void handleReceived(MeshPacket *p);
|
||||
|
||||
/** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */
|
||||
void abortSendAndNak(Routing_Error err, MeshPacket *p);
|
||||
};
|
||||
|
||||
extern Router *router;
|
||||
|
@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg;
|
||||
#define DeviceState_fields &DeviceState_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define DeviceState_size 6119
|
||||
#define DeviceState_size 6125
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -80,7 +80,9 @@ typedef enum _Routing_Error {
|
||||
Routing_Error_GOT_NAK = 2,
|
||||
Routing_Error_TIMEOUT = 3,
|
||||
Routing_Error_NO_INTERFACE = 4,
|
||||
Routing_Error_MAX_RETRANSMIT = 5
|
||||
Routing_Error_MAX_RETRANSMIT = 5,
|
||||
Routing_Error_NO_CHANNEL = 6,
|
||||
Routing_Error_TOO_LARGE = 7
|
||||
} Routing_Error;
|
||||
|
||||
typedef enum _MeshPacket_Priority {
|
||||
@ -240,7 +242,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
|
||||
typedef struct _MeshPacket {
|
||||
uint32_t from;
|
||||
uint32_t to;
|
||||
uint8_t channel_index;
|
||||
uint32_t channel;
|
||||
pb_size_t which_payloadVariant;
|
||||
union {
|
||||
Data decoded;
|
||||
@ -340,8 +342,8 @@ typedef struct _ToRadio {
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1))
|
||||
|
||||
#define _Routing_Error_MIN Routing_Error_NONE
|
||||
#define _Routing_Error_MAX Routing_Error_MAX_RETRANSMIT
|
||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_MAX_RETRANSMIT+1))
|
||||
#define _Routing_Error_MAX Routing_Error_TOO_LARGE
|
||||
#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_TOO_LARGE+1))
|
||||
|
||||
#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET
|
||||
#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX
|
||||
@ -488,7 +490,7 @@ extern "C" {
|
||||
#define Channel_role_tag 3
|
||||
#define MeshPacket_from_tag 1
|
||||
#define MeshPacket_to_tag 2
|
||||
#define MeshPacket_channel_index_tag 3
|
||||
#define MeshPacket_channel_tag 3
|
||||
#define MeshPacket_decoded_tag 4
|
||||
#define MeshPacket_encrypted_tag 5
|
||||
#define MeshPacket_id_tag 6
|
||||
@ -571,7 +573,7 @@ X(a, STATIC, SINGULAR, FIXED32, source, 5)
|
||||
#define MeshPacket_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, from, 1) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, to, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, channel_index, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, channel, 3) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 4) \
|
||||
X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 5) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, id, 6) \
|
||||
@ -771,7 +773,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
|
||||
#define RouteDiscovery_size 40
|
||||
#define Routing_size 47
|
||||
#define Data_size 255
|
||||
#define MeshPacket_size 294
|
||||
#define MeshPacket_size 297
|
||||
#define ChannelSettings_size 87
|
||||
#define Channel_size 94
|
||||
#define RadioConfig_size 308
|
||||
@ -780,7 +782,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
|
||||
#define MyNodeInfo_size 89
|
||||
#define LogRecord_size 81
|
||||
#define FromRadio_size 317
|
||||
#define ToRadio_size 297
|
||||
#define ToRadio_size 300
|
||||
#define AdminMessage_size 311
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Loading…
Reference in New Issue
Block a user