* refactored the hasSeen(Packet) stuff.

This commit is contained in:
Scott Powell 2025-01-14 06:43:03 +11:00
parent 8983584dd8
commit 20fccac2b7
10 changed files with 68 additions and 133 deletions

View file

@ -7,7 +7,7 @@
#include <helpers/RadioLibWrappers.h> #include <helpers/RadioLibWrappers.h>
#include <helpers/ArduinoHelpers.h> #include <helpers/ArduinoHelpers.h>
#include <helpers/StaticPoolPacketManager.h> #include <helpers/StaticPoolPacketManager.h>
#include <helpers/SimpleSeenTable.h> #include <helpers/SimpleMeshTables.h>
/* ------------------------------ Config -------------------------------- */ /* ------------------------------ Config -------------------------------- */
@ -21,7 +21,6 @@
/* ------------------------------ Code -------------------------------- */ /* ------------------------------ Code -------------------------------- */
class MyMesh : public mesh::Mesh { class MyMesh : public mesh::Mesh {
SimpleSeenTable* _table;
uint32_t last_advert_timestamp = 0; uint32_t last_advert_timestamp = 0;
mesh::Identity server_id; mesh::Identity server_id;
uint8_t server_secret[PUB_KEY_SIZE]; uint8_t server_secret[PUB_KEY_SIZE];
@ -54,8 +53,6 @@ protected:
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, uint8_t* data, size_t len) override { void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, uint8_t* data, size_t len) override {
if (type == PAYLOAD_TYPE_RESPONSE) { if (type == PAYLOAD_TYPE_RESPONSE) {
if (_table->hasSeenPacket(packet)) return;
Serial.println("Received PING Reply!"); Serial.println("Received PING Reply!");
if (packet->isRouteFlood()) { if (packet->isRouteFlood()) {
@ -67,8 +64,6 @@ protected:
} }
void onPeerPathRecv(mesh::Packet* packet, int sender_idx, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override { void onPeerPathRecv(mesh::Packet* packet, int sender_idx, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override {
if (_table->hasSeenPacket(packet)) return;
// must be from server_id // must be from server_id
Serial.printf("PATH to server, path_len=%d\n", (uint32_t) path_len); Serial.printf("PATH to server, path_len=%d\n", (uint32_t) path_len);
@ -86,8 +81,8 @@ protected:
} }
public: public:
MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleSeenTable& table) MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16)), _table(&table) : mesh::Mesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables)
{ {
} }
@ -110,9 +105,9 @@ public:
SPIClass spi; SPIClass spi;
StdRNG fast_rng; StdRNG fast_rng;
SimpleSeenTable table; SimpleMeshTables tables;
SX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); SX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
MyMesh the_mesh(*new RadioLibWrapper(radio, board), fast_rng, *new VolatileRTCClock(), table); MyMesh the_mesh(*new RadioLibWrapper(radio, board), fast_rng, *new VolatileRTCClock(), tables);
unsigned long nextPing; unsigned long nextPing;
void halt() { void halt() {

View file

@ -7,6 +7,7 @@
#include <helpers/RadioLibWrappers.h> #include <helpers/RadioLibWrappers.h>
#include <helpers/ArduinoHelpers.h> #include <helpers/ArduinoHelpers.h>
#include <helpers/StaticPoolPacketManager.h> #include <helpers/StaticPoolPacketManager.h>
#include <helpers/SimpleMeshTables.h>
/* ------------------------------ Config -------------------------------- */ /* ------------------------------ Config -------------------------------- */
@ -56,7 +57,7 @@ protected:
auto client = putClient(sender); // add to known clients (if not already known) auto client = putClient(sender); // add to known clients (if not already known)
if (client == NULL || timestamp <= client->last_timestamp) { if (client == NULL || timestamp <= client->last_timestamp) {
return; // FATAL: client table is full -OR- replay attack -OR- have seen this packet before return; // FATAL: client table is full -OR- replay attack
} }
client->last_timestamp = timestamp; client->last_timestamp = timestamp;
@ -123,8 +124,8 @@ protected:
} }
public: public:
MyMesh(mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc) MyMesh(mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(16)) : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(16), tables)
{ {
num_clients = 0; num_clients = 0;
} }
@ -132,8 +133,9 @@ public:
SPIClass spi; SPIClass spi;
StdRNG fast_rng; StdRNG fast_rng;
SimpleMeshTables tables;
SX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); SX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
MyMesh the_mesh(*new RadioLibWrapper(radio, board), *new ArduinoMillis(), fast_rng, *new VolatileRTCClock()); MyMesh the_mesh(*new RadioLibWrapper(radio, board), *new ArduinoMillis(), fast_rng, *new VolatileRTCClock(), tables);
unsigned long nextAnnounce; unsigned long nextAnnounce;

View file

@ -53,7 +53,6 @@ struct ClientInfo {
class MyMesh : public mesh::Mesh { class MyMesh : public mesh::Mesh {
RadioLibWrapper* my_radio; RadioLibWrapper* my_radio;
mesh::MeshTables* _tables;
float airtime_factor; float airtime_factor;
uint8_t reply_data[MAX_PACKET_PAYLOAD]; uint8_t reply_data[MAX_PACKET_PAYLOAD];
int num_clients; int num_clients;
@ -145,12 +144,6 @@ protected:
} }
bool allowPacketForward(const mesh::Packet* packet) override { bool allowPacketForward(const mesh::Packet* packet) override {
uint8_t hash[MAX_HASH_SIZE];
packet->calculatePacketHash(hash);
if (_tables->hasForwarded(hash)) return false; // has already been forwarded
_tables->setHasForwarded(hash); // mark packet as forwarded
return true; // Yes, allow packet to be forwarded return true; // Yes, allow packet to be forwarded
} }
@ -162,7 +155,7 @@ protected:
if (memcmp(&data[4], ADMIN_PASSWORD, 8) == 0) { // check for valid password if (memcmp(&data[4], ADMIN_PASSWORD, 8) == 0) { // check for valid password
auto client = putClient(sender); // add to known clients (if not already known) auto client = putClient(sender); // add to known clients (if not already known)
if (client == NULL || timestamp <= client->last_timestamp) { if (client == NULL || timestamp <= client->last_timestamp) {
return; // FATAL: client table is full -OR- replay attack -OR- have seen this packet before return; // FATAL: client table is full -OR- replay attack
} }
client->last_timestamp = timestamp; client->last_timestamp = timestamp;
@ -222,7 +215,7 @@ protected:
uint32_t timestamp; uint32_t timestamp;
memcpy(&timestamp, data, 4); memcpy(&timestamp, data, 4);
if (timestamp > client->last_timestamp) { // prevent replay attacks AND receiving via multiple paths if (timestamp > client->last_timestamp) { // prevent replay attacks
int reply_len = handleRequest(client, &data[4], len - 4); int reply_len = handleRequest(client, &data[4], len - 4);
if (reply_len == 0) return; // invalid command if (reply_len == 0) return; // invalid command
@ -267,7 +260,7 @@ protected:
public: public:
MyMesh(RadioLibWrapper& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables) MyMesh(RadioLibWrapper& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32)), _tables(&tables) : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables)
{ {
my_radio = &radio; my_radio = &radio;
airtime_factor = 5.0; // 1/6th airtime_factor = 5.0; // 1/6th

View file

@ -7,7 +7,7 @@
#include <helpers/RadioLibWrappers.h> #include <helpers/RadioLibWrappers.h>
#include <helpers/ArduinoHelpers.h> #include <helpers/ArduinoHelpers.h>
#include <helpers/StaticPoolPacketManager.h> #include <helpers/StaticPoolPacketManager.h>
#include <helpers/SimpleSeenTable.h> #include <helpers/SimpleMeshTables.h>
/* ---------------------------------- CONFIGURATION ------------------------------------- */ /* ---------------------------------- CONFIGURATION ------------------------------------- */
@ -52,7 +52,6 @@ struct ContactInfo {
class MyMesh : public mesh::Mesh { class MyMesh : public mesh::Mesh {
public: public:
SimpleSeenTable* _table;
ContactInfo contacts[MAX_CONTACTS]; ContactInfo contacts[MAX_CONTACTS];
int num_contacts; int num_contacts;
@ -111,7 +110,6 @@ protected:
// NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins. // NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins.
// For flood mode, the path may not be the 'best' in terms of hops. // For flood mode, the path may not be the 'best' in terms of hops.
// FUTURE: could send back multiple paths, using createPathReturn(), and let sender choose which to use(?) // FUTURE: could send back multiple paths, using createPathReturn(), and let sender choose which to use(?)
if (_table->hasSeenPacket(packet)) return;
int i = matching_peer_indexes[sender_idx]; int i = matching_peer_indexes[sender_idx];
if (i < 0 && i >= num_contacts) { if (i < 0 && i >= num_contacts) {
@ -152,8 +150,6 @@ protected:
} }
void onPeerPathRecv(mesh::Packet* packet, int sender_idx, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override { void onPeerPathRecv(mesh::Packet* packet, int sender_idx, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override {
if (_table->hasSeenPacket(packet)) return;
int i = matching_peer_indexes[sender_idx]; int i = matching_peer_indexes[sender_idx];
if (i < 0 && i >= num_contacts) { if (i < 0 && i >= num_contacts) {
MESH_DEBUG_PRINTLN("onPeerPathRecv: Invalid sender idx: %d", i); MESH_DEBUG_PRINTLN("onPeerPathRecv: Invalid sender idx: %d", i);
@ -199,8 +195,8 @@ protected:
public: public:
uint32_t expected_ack_crc; uint32_t expected_ack_crc;
MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleSeenTable& table) MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables)
: mesh::Mesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16)), _table(&table) : mesh::Mesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables)
{ {
num_contacts = 0; num_contacts = 0;
} }
@ -233,9 +229,9 @@ public:
SPIClass spi; SPIClass spi;
StdRNG fast_rng; StdRNG fast_rng;
SimpleSeenTable table; SimpleMeshTables tables;
SX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); SX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
MyMesh the_mesh(*new RadioLibWrapper(radio, board), fast_rng, *new VolatileRTCClock(), table); MyMesh the_mesh(*new RadioLibWrapper(radio, board), fast_rng, *new VolatileRTCClock(), tables);
void halt() { void halt() {
while (1) ; while (1) ;

View file

@ -6,7 +6,7 @@
#include <RadioLib.h> #include <RadioLib.h>
#include <helpers/CustomSX1262Wrapper.h> #include <helpers/CustomSX1262Wrapper.h>
#include <helpers/ArduinoHelpers.h> #include <helpers/ArduinoHelpers.h>
#include <helpers/SimpleSeenTable.h> #include <helpers/SimpleMeshTables.h>
#include <helpers/StaticPoolPacketManager.h> #include <helpers/StaticPoolPacketManager.h>
/* ---------------------------------- CONFIGURATION ------------------------------------- */ /* ---------------------------------- CONFIGURATION ------------------------------------- */
@ -41,7 +41,6 @@ struct RepeaterStats {
}; };
class MyMesh : public mesh::Mesh { class MyMesh : public mesh::Mesh {
SimpleSeenTable* _table;
uint32_t last_advert_timestamp = 0; uint32_t last_advert_timestamp = 0;
mesh::Identity server_id; mesh::Identity server_id;
uint8_t server_secret[PUB_KEY_SIZE]; uint8_t server_secret[PUB_KEY_SIZE];
@ -105,8 +104,6 @@ protected:
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, uint8_t* data, size_t len) override { void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, uint8_t* data, size_t len) override {
if (type == PAYLOAD_TYPE_RESPONSE) { if (type == PAYLOAD_TYPE_RESPONSE) {
if (_table->hasSeenPacket(packet)) return;
handleResponse(data, len); handleResponse(data, len);
if (packet->isRouteFlood()) { if (packet->isRouteFlood()) {
@ -118,8 +115,6 @@ protected:
} }
void onPeerPathRecv(mesh::Packet* packet, int sender_idx, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override { void onPeerPathRecv(mesh::Packet* packet, int sender_idx, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override {
if (_table->hasSeenPacket(packet)) return;
// must be from server_id // must be from server_id
Serial.printf("PATH to repeater, path_len=%d\n", (uint32_t) path_len); Serial.printf("PATH to repeater, path_len=%d\n", (uint32_t) path_len);
@ -137,8 +132,8 @@ protected:
} }
public: public:
MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleSeenTable& table) MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16)), _table(&table) : mesh::Mesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables)
{ {
} }
@ -206,14 +201,14 @@ public:
}; };
StdRNG fast_rng; StdRNG fast_rng;
SimpleSeenTable table; SimpleMeshTables tables;
#if defined(P_LORA_SCLK) #if defined(P_LORA_SCLK)
SPIClass spi; SPIClass spi;
CustomSX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); CustomSX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else #else
CustomSX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); CustomSX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif #endif
MyMesh the_mesh(*new CustomSX1262Wrapper(radio, board), fast_rng, *new VolatileRTCClock(), table); MyMesh the_mesh(*new CustomSX1262Wrapper(radio, board), fast_rng, *new VolatileRTCClock(), tables);
void halt() { void halt() {
while (1) ; while (1) ;

View file

@ -36,6 +36,8 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) { if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) {
if (self_id.isHashMatch(pkt->path) && allowPacketForward(pkt)) { if (self_id.isHashMatch(pkt->path) && allowPacketForward(pkt)) {
if (_tables->hasSeen(pkt)) return ACTION_RELEASE; // don't retransmit!
// remove our hash from 'path', then re-broadcast // remove our hash from 'path', then re-broadcast
pkt->path_len -= PATH_HASH_SIZE; pkt->path_len -= PATH_HASH_SIZE;
memcpy(pkt->path, &pkt->path[PATH_HASH_SIZE], pkt->path_len); memcpy(pkt->path, &pkt->path[PATH_HASH_SIZE], pkt->path_len);
@ -53,7 +55,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
memcpy(&ack_crc, &pkt->payload[i], 4); i += 4; memcpy(&ack_crc, &pkt->payload[i], 4); i += 4;
if (i > pkt->payload_len) { if (i > pkt->payload_len) {
MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete ACK packet"); MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete ACK packet");
} else { } else if (!_tables->hasSeen(pkt)) {
onAckRecv(pkt, ack_crc); onAckRecv(pkt, ack_crc);
action = routeRecvPacket(pkt); action = routeRecvPacket(pkt);
} }
@ -70,7 +72,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
if (i + 2 >= pkt->payload_len) { if (i + 2 >= pkt->payload_len) {
MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete data packet"); MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete data packet");
} else { } else if (!_tables->hasSeen(pkt)) {
if (self_id.isHashMatch(&dest_hash)) { if (self_id.isHashMatch(&dest_hash)) {
// scan contacts DB, for all matching hashes of 'src_hash' (max 4 matches supported ATM) // scan contacts DB, for all matching hashes of 'src_hash' (max 4 matches supported ATM)
int num = searchPeersByHash(&src_hash); int num = searchPeersByHash(&src_hash);
@ -115,7 +117,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
if (i + 2 >= pkt->payload_len) { if (i + 2 >= pkt->payload_len) {
MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete data packet"); MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete data packet");
} else { } else if (!_tables->hasSeen(pkt)) {
if (self_id.isHashMatch(&dest_hash)) { if (self_id.isHashMatch(&dest_hash)) {
Identity sender(sender_pub_key); Identity sender(sender_pub_key);
@ -141,7 +143,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
if (i + 2 >= pkt->payload_len) { if (i + 2 >= pkt->payload_len) {
MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete data packet"); MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete data packet");
} else { } else if (!_tables->hasSeen(pkt)) {
// scan channels DB, for all matching hashes of 'channel_hash' (max 2 matches supported ATM) // scan channels DB, for all matching hashes of 'channel_hash' (max 2 matches supported ATM)
GroupChannel channels[2]; GroupChannel channels[2];
int num = searchChannelsByHash(&channel_hash, channels, 2); int num = searchChannelsByHash(&channel_hash, channels, 2);
@ -170,7 +172,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
if (i > pkt->payload_len) { if (i > pkt->payload_len) {
MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete advertisement packet"); MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): incomplete advertisement packet");
} else { } else if (!_tables->hasSeen(pkt)) {
uint8_t* app_data = &pkt->payload[i]; uint8_t* app_data = &pkt->payload[i];
int app_data_len = pkt->payload_len - i; int app_data_len = pkt->payload_len - i;
if (app_data_len > MAX_ADVERT_DATA_SIZE) { app_data_len = MAX_ADVERT_DATA_SIZE; } if (app_data_len > MAX_ADVERT_DATA_SIZE) { app_data_len = MAX_ADVERT_DATA_SIZE; }
@ -198,7 +200,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
} }
default: default:
MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): unknown payload type, header: %d", (int) pkt->header); MESH_DEBUG_PRINTLN("Mesh::onRecvPacket(): unknown payload type, header: %d", (int) pkt->header);
action = routeRecvPacket(pkt); // Don't flood route unknown packet types! action = routeRecvPacket(pkt);
break; break;
} }
return action; return action;
@ -382,7 +384,7 @@ void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) {
packet->header |= ROUTE_TYPE_FLOOD; packet->header |= ROUTE_TYPE_FLOOD;
packet->path_len = 0; packet->path_len = 0;
allowPacketForward(packet); // mark this packet as already sent in case it is rebroadcast back to us _tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
uint8_t pri; uint8_t pri;
if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) { if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
@ -401,7 +403,7 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin
memcpy(packet->path, path, packet->path_len = path_len); memcpy(packet->path, path, packet->path_len = path_len);
allowPacketForward(packet); // mark this packet as already sent in case it is rebroadcast back to us _tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
sendPacket(packet, 0, delay_millis); sendPacket(packet, 0, delay_millis);
} }
@ -412,7 +414,7 @@ void Mesh::sendZeroHop(Packet* packet, uint32_t delay_millis) {
packet->path_len = 0; // path_len of zero means Zero Hop packet->path_len = 0; // path_len of zero means Zero Hop
allowPacketForward(packet); // mark this packet as already sent in case it is rebroadcast back to us _tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
sendPacket(packet, 0, delay_millis); sendPacket(packet, 0, delay_millis);
} }

View file

@ -26,6 +26,14 @@ public:
uint8_t secret[PUB_KEY_SIZE]; uint8_t secret[PUB_KEY_SIZE];
}; };
/**
* An abstraction of the data tables needed to be maintained
*/
class MeshTables {
public:
virtual bool hasSeen(const Packet* packet) = 0;
};
/** /**
* \brief The next layer in the basic Dispatcher task, Mesh recognises the particular Payload TYPES, * \brief The next layer in the basic Dispatcher task, Mesh recognises the particular Payload TYPES,
* and provides virtual methods for sub-classes on handling incoming, and also preparing outbound Packets. * and provides virtual methods for sub-classes on handling incoming, and also preparing outbound Packets.
@ -33,6 +41,7 @@ public:
class Mesh : public Dispatcher { class Mesh : public Dispatcher {
RTCClock* _rtc; RTCClock* _rtc;
RNG* _rng; RNG* _rng;
MeshTables* _tables;
protected: protected:
DispatcherAction onRecvPacket(Packet* pkt) override; DispatcherAction onRecvPacket(Packet* pkt) override;
@ -117,8 +126,8 @@ protected:
*/ */
virtual void onAckRecv(Packet* packet, uint32_t ack_crc) { } virtual void onAckRecv(Packet* packet, uint32_t ack_crc) { }
Mesh(Radio& radio, MillisecondClock& ms, RNG& rng, RTCClock& rtc, PacketManager& mgr) Mesh(Radio& radio, MillisecondClock& ms, RNG& rng, RTCClock& rtc, PacketManager& mgr, MeshTables& tables)
: Dispatcher(radio, ms, mgr), _rng(&rng), _rtc(&rtc) : Dispatcher(radio, ms, mgr), _rng(&rng), _rtc(&rtc), _tables(&tables)
{ {
} }

View file

@ -1,16 +0,0 @@
#pragma once
#include <Mesh.h>
namespace mesh {
/**
* An abstraction of the data tables needed to be maintained, for the routing engine.
*/
class MeshTables {
public:
virtual bool hasForwarded(const uint8_t* packet_hash) const = 0;
virtual void setHasForwarded(const uint8_t* packet_hash) = 0;
};
}

View file

@ -1,56 +1,48 @@
#pragma once #pragma once
#include <MeshTables.h> #include <Mesh.h>
#ifdef ESP32 #ifdef ESP32
#include <FS.h> #include <FS.h>
#endif #endif
#define MAX_PACKET_HASHES 64 #define MAX_PACKET_HASHES 128
class SimpleMeshTables : public mesh::MeshTables { class SimpleMeshTables : public mesh::MeshTables {
uint8_t _fwd_hashes[MAX_PACKET_HASHES*MAX_HASH_SIZE]; uint8_t _hashes[MAX_PACKET_HASHES*MAX_HASH_SIZE];
int _next_fwd_idx; int _next_idx;
int lookupHashIndex(const uint8_t* hash) const {
const uint8_t* sp = _fwd_hashes;
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) return i;
}
return -1;
}
public: public:
SimpleMeshTables() { SimpleMeshTables() {
memset(_fwd_hashes, 0, sizeof(_fwd_hashes)); memset(_hashes, 0, sizeof(_hashes));
_next_fwd_idx = 0; _next_idx = 0;
} }
#ifdef ESP32 #ifdef ESP32
void restoreFrom(File f) { void restoreFrom(File f) {
f.read(_fwd_hashes, sizeof(_fwd_hashes)); f.read(_hashes, sizeof(_hashes));
f.read((uint8_t *) &_next_fwd_idx, sizeof(_next_fwd_idx)); f.read((uint8_t *) &_next_idx, sizeof(_next_idx));
} }
void saveTo(File f) { void saveTo(File f) {
f.write(_fwd_hashes, sizeof(_fwd_hashes)); f.write(_hashes, sizeof(_hashes));
f.write((const uint8_t *) &_next_fwd_idx, sizeof(_next_fwd_idx)); f.write((const uint8_t *) &_next_idx, sizeof(_next_idx));
} }
#endif #endif
bool hasForwarded(const uint8_t* packet_hash) const override { bool hasSeen(const mesh::Packet* packet) override {
int i = lookupHashIndex(packet_hash); uint8_t hash[MAX_HASH_SIZE];
return i >= 0; packet->calculatePacketHash(hash);
}
void setHasForwarded(const uint8_t* packet_hash) override { const uint8_t* sp = _hashes;
int i = lookupHashIndex(packet_hash); for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
if (i >= 0) { if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) return true;
// already in table
} else {
memcpy(&_fwd_hashes[_next_fwd_idx*MAX_HASH_SIZE], packet_hash, MAX_HASH_SIZE);
_next_fwd_idx = (_next_fwd_idx + 1) % MAX_PACKET_HASHES; // cyclic table
} }
memcpy(&_hashes[_next_idx*MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
_next_idx = (_next_idx + 1) % MAX_PACKET_HASHES; // cyclic table
return false;
} }
}; };

View file

@ -1,33 +0,0 @@
#pragma once
#include <Packet.h>
#include <string.h>
#define MAX_PACKET_HASHES 64
class SimpleSeenTable {
uint8_t _hashes[MAX_PACKET_HASHES*MAX_HASH_SIZE];
int _next_idx;
public:
SimpleSeenTable() {
memset(_hashes, 0, sizeof(_hashes));
_next_idx = 0;
}
bool hasSeenPacket(const mesh::Packet* packet) {
uint8_t hash[MAX_HASH_SIZE];
packet->calculatePacketHash(hash);
const uint8_t* sp = _hashes;
for (int i = 0; i < MAX_PACKET_HASHES; i++, sp += MAX_HASH_SIZE) {
if (memcmp(hash, sp, MAX_HASH_SIZE) == 0) return true;
}
memcpy(&_hashes[_next_idx*MAX_HASH_SIZE], hash, MAX_HASH_SIZE);
_next_idx = (_next_idx + 1) % MAX_PACKET_HASHES; // cyclic table
return false;
}
};