mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Merge 5266ffcaf3 into dee3e26ac0
This commit is contained in:
commit
80dfa37b47
2 changed files with 432 additions and 0 deletions
|
|
@ -43,6 +43,9 @@
|
|||
|
||||
#define FIRMWARE_VER_LEVEL 2
|
||||
|
||||
#define PATH_BLACKLIST_FILE "/path_bl"
|
||||
#define CHAN_BLACKLIST_FILE "/chan_bl"
|
||||
|
||||
#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS
|
||||
#define REQ_TYPE_KEEP_ALIVE 0x02
|
||||
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
|
||||
|
|
@ -545,6 +548,295 @@ uint32_t MyMesh::getDirectRetransmitDelay(const mesh::Packet *packet) {
|
|||
return getRNG()->nextInt(0, 5*t + 1);
|
||||
}
|
||||
|
||||
/* ----------------------- Blacklist helpers -------------------------------- */
|
||||
|
||||
// Returns true if any path entry in the packet matches a path-prefix blacklist entry.
|
||||
// Comparison uses min(entry.len, hash_size) bytes, so shorter entries match any hash size.
|
||||
bool MyMesh::isPathBlacklisted(const mesh::Packet* packet) const {
|
||||
uint8_t hash_size = packet->getPathHashSize();
|
||||
uint8_t hash_count = packet->getPathHashCount();
|
||||
const uint8_t* ptr = packet->path;
|
||||
for (uint8_t h = 0; h < hash_count; h++, ptr += hash_size) {
|
||||
for (int b = 0; b < MAX_BLACKLIST_ENTRIES; b++) {
|
||||
if (_path_blacklist[b].len == 0) continue;
|
||||
uint8_t cmp_len = (_path_blacklist[b].len < hash_size) ? _path_blacklist[b].len : hash_size;
|
||||
if (memcmp(ptr, _path_blacklist[b].prefix, cmp_len) == 0) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if the channel hash at the start of a GRP_TXT/GRP_DATA payload matches
|
||||
// a channel-hash blacklist entry (hex prefix or #channel_name with decrypt verification).
|
||||
bool MyMesh::isChanBlacklisted(const mesh::Packet* packet) const {
|
||||
uint8_t pt = packet->getPayloadType();
|
||||
if (pt != PAYLOAD_TYPE_GRP_TXT && pt != PAYLOAD_TYPE_GRP_DATA) return false;
|
||||
if (packet->payload_len < PATH_HASH_SIZE) return false;
|
||||
|
||||
// Check hex prefix entries
|
||||
for (int b = 0; b < MAX_BLACKLIST_ENTRIES; b++) {
|
||||
if (_chan_blacklist[b].len == 0) continue;
|
||||
uint8_t avail = (packet->payload_len < MAX_PATH_PREFIX_LEN) ? (uint8_t)packet->payload_len : MAX_PATH_PREFIX_LEN;
|
||||
uint8_t cmp_len = (_chan_blacklist[b].len < avail) ? _chan_blacklist[b].len : avail;
|
||||
if (memcmp(packet->payload, _chan_blacklist[b].prefix, cmp_len) == 0) return true;
|
||||
}
|
||||
|
||||
// Check #channel_name entries with test decryption
|
||||
if (_num_chan_name_filters > 0 && packet->payload_len > PATH_HASH_SIZE + CIPHER_MAC_SIZE) {
|
||||
uint8_t channel_hash = packet->payload[0];
|
||||
const uint8_t* macAndData = &packet->payload[PATH_HASH_SIZE]; // MAC + encrypted data
|
||||
int enc_len = packet->payload_len - PATH_HASH_SIZE;
|
||||
|
||||
for (int i = 0; i < _num_chan_name_filters; i++) {
|
||||
// Quick hash check first
|
||||
if (channel_hash != _chan_name_filters[i].hash[0]) continue;
|
||||
// Try to decrypt to verify this is actually the channel
|
||||
uint8_t tmp[MAX_PACKET_PAYLOAD];
|
||||
int len = mesh::Utils::MACThenDecrypt(_chan_name_filters[i].secret, tmp, macAndData, enc_len);
|
||||
if (len > 0) return true; // Successfully decrypted, confirmed channel match
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MyMesh::addToBlacklist(BlacklistEntry* list, const uint8_t* prefix, uint8_t len) {
|
||||
if (len == 0 || len > MAX_PATH_PREFIX_LEN) return false;
|
||||
// if already present, consider success
|
||||
for (int i = 0; i < MAX_BLACKLIST_ENTRIES; i++) {
|
||||
if (list[i].len == len && memcmp(list[i].prefix, prefix, len) == 0) return true;
|
||||
}
|
||||
// find an empty slot
|
||||
for (int i = 0; i < MAX_BLACKLIST_ENTRIES; i++) {
|
||||
if (list[i].len == 0) {
|
||||
list[i].len = len;
|
||||
memcpy(list[i].prefix, prefix, len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // list is full
|
||||
}
|
||||
|
||||
bool MyMesh::removeFromBlacklist(BlacklistEntry* list, const uint8_t* prefix, uint8_t len) {
|
||||
for (int i = 0; i < MAX_BLACKLIST_ENTRIES; i++) {
|
||||
if (list[i].len == len && memcmp(list[i].prefix, prefix, len) == 0) {
|
||||
list[i].len = 0; // mark slot as empty
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MyMesh::formatBlacklist(const BlacklistEntry* list, char* reply) {
|
||||
char* dp = reply;
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_BLACKLIST_ENTRIES; i++) {
|
||||
if (list[i].len == 0) continue;
|
||||
if (count > 0) *dp++ = '\n';
|
||||
mesh::Utils::toHex(dp, list[i].prefix, list[i].len);
|
||||
dp += list[i].len * 2;
|
||||
count++;
|
||||
}
|
||||
if (count == 0) {
|
||||
strcpy(reply, "-none-");
|
||||
} else {
|
||||
*dp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MyMesh::loadBlacklist(const char* fname, BlacklistEntry* list) {
|
||||
memset(list, 0, sizeof(BlacklistEntry) * MAX_BLACKLIST_ENTRIES);
|
||||
#if defined(RP2040_PLATFORM)
|
||||
File f = _fs->open(fname, "r");
|
||||
#else
|
||||
File f = _fs->open(fname);
|
||||
#endif
|
||||
if (!f) return;
|
||||
int idx = 0;
|
||||
char line[MAX_PATH_PREFIX_LEN * 2 + 4];
|
||||
int line_len = 0;
|
||||
while (f.available() && idx < MAX_BLACKLIST_ENTRIES) {
|
||||
int c = f.read();
|
||||
if (c < 0) break;
|
||||
if (c == '\n' || c == '\r') {
|
||||
if (line_len >= 2 && (line_len % 2 == 0)) {
|
||||
line[line_len] = 0;
|
||||
uint8_t prefix[MAX_PATH_PREFIX_LEN];
|
||||
int byte_len = line_len / 2;
|
||||
if (byte_len <= MAX_PATH_PREFIX_LEN && mesh::Utils::fromHex(prefix, byte_len, line)) {
|
||||
list[idx].len = (uint8_t)byte_len;
|
||||
memcpy(list[idx].prefix, prefix, byte_len);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
line_len = 0;
|
||||
} else if (line_len < (int)(sizeof(line) - 1)) {
|
||||
line[line_len++] = (char)c;
|
||||
}
|
||||
}
|
||||
// handle last line with no trailing newline
|
||||
if (line_len >= 2 && (line_len % 2 == 0) && idx < MAX_BLACKLIST_ENTRIES) {
|
||||
line[line_len] = 0;
|
||||
uint8_t prefix[MAX_PATH_PREFIX_LEN];
|
||||
int byte_len = line_len / 2;
|
||||
if (byte_len <= MAX_PATH_PREFIX_LEN && mesh::Utils::fromHex(prefix, byte_len, line)) {
|
||||
list[idx].len = (uint8_t)byte_len;
|
||||
memcpy(list[idx].prefix, prefix, byte_len);
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
void MyMesh::saveBlacklist(const char* fname, const BlacklistEntry* list) {
|
||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||
_fs->remove(fname);
|
||||
File f = _fs->open(fname, FILE_O_WRITE);
|
||||
#elif defined(RP2040_PLATFORM)
|
||||
File f = _fs->open(fname, "w");
|
||||
#else
|
||||
File f = _fs->open(fname, "w", true);
|
||||
#endif
|
||||
if (!f) return;
|
||||
for (int i = 0; i < MAX_BLACKLIST_ENTRIES; i++) {
|
||||
if (list[i].len == 0) continue;
|
||||
char hex[MAX_PATH_PREFIX_LEN * 2 + 2];
|
||||
mesh::Utils::toHex(hex, list[i].prefix, list[i].len);
|
||||
f.println(hex);
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
/* ------------------- Channel name filter helpers -------------------------- */
|
||||
|
||||
void MyMesh::deriveChanNameFilter(ChanNameFilter& entry, const char* name) {
|
||||
// Derive channel secret: first 16 bytes of sha256(name), zero-padded to PUB_KEY_SIZE
|
||||
// to match GroupChannel.secret layout (MACThenDecrypt reads PUB_KEY_SIZE bytes)
|
||||
uint8_t full_hash[32];
|
||||
mesh::Utils::sha256(full_hash, 32, (const uint8_t*)name, strlen(name));
|
||||
memset(entry.secret, 0, sizeof(entry.secret));
|
||||
memcpy(entry.secret, full_hash, CIPHER_KEY_SIZE);
|
||||
// Derive channel hash from the secret (using 16-byte key length, matching addChannel)
|
||||
mesh::Utils::sha256(entry.hash, sizeof(entry.hash), entry.secret, CIPHER_KEY_SIZE);
|
||||
StrHelper::strncpy(entry.name, name, sizeof(entry.name));
|
||||
}
|
||||
|
||||
bool MyMesh::addChanNameFilter(const char* name) {
|
||||
// Check for duplicate
|
||||
for (int i = 0; i < _num_chan_name_filters; i++) {
|
||||
if (strcmp(_chan_name_filters[i].name, name) == 0) return true; // already exists
|
||||
}
|
||||
if (_num_chan_name_filters >= MAX_CHAN_NAME_FILTERS) return false; // full
|
||||
deriveChanNameFilter(_chan_name_filters[_num_chan_name_filters], name);
|
||||
_num_chan_name_filters++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MyMesh::removeChanNameFilter(const char* name) {
|
||||
for (int i = 0; i < _num_chan_name_filters; i++) {
|
||||
if (strcmp(_chan_name_filters[i].name, name) == 0) {
|
||||
// shift remaining entries down
|
||||
for (int j = i; j < _num_chan_name_filters - 1; j++) {
|
||||
_chan_name_filters[j] = _chan_name_filters[j + 1];
|
||||
}
|
||||
_num_chan_name_filters--;
|
||||
memset(&_chan_name_filters[_num_chan_name_filters], 0, sizeof(ChanNameFilter));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MyMesh::loadChanBlacklist(const char* fname) {
|
||||
// Load both hex prefix entries and #channel_name entries from the same file
|
||||
loadBlacklist(fname, _chan_blacklist); // loads hex entries into _chan_blacklist
|
||||
|
||||
// Now re-read the file to pick up #channel_name lines
|
||||
_num_chan_name_filters = 0;
|
||||
memset(_chan_name_filters, 0, sizeof(_chan_name_filters));
|
||||
#if defined(RP2040_PLATFORM)
|
||||
File f = _fs->open(fname, "r");
|
||||
#else
|
||||
File f = _fs->open(fname);
|
||||
#endif
|
||||
if (!f) return;
|
||||
char line[40];
|
||||
int line_len = 0;
|
||||
while (f.available() && _num_chan_name_filters < MAX_CHAN_NAME_FILTERS) {
|
||||
int c = f.read();
|
||||
if (c < 0) break;
|
||||
if (c == '\n' || c == '\r') {
|
||||
if (line_len > 0 && line[0] == '#') {
|
||||
line[line_len] = 0;
|
||||
deriveChanNameFilter(_chan_name_filters[_num_chan_name_filters], line);
|
||||
_num_chan_name_filters++;
|
||||
}
|
||||
line_len = 0;
|
||||
} else if (line_len < (int)(sizeof(line) - 1)) {
|
||||
line[line_len++] = (char)c;
|
||||
}
|
||||
}
|
||||
// handle last line with no trailing newline
|
||||
if (line_len > 0 && line[0] == '#' && _num_chan_name_filters < MAX_CHAN_NAME_FILTERS) {
|
||||
line[line_len] = 0;
|
||||
deriveChanNameFilter(_chan_name_filters[_num_chan_name_filters], line);
|
||||
_num_chan_name_filters++;
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
void MyMesh::saveChanBlacklist(const char* fname) {
|
||||
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
||||
_fs->remove(fname);
|
||||
File f = _fs->open(fname, FILE_O_WRITE);
|
||||
#elif defined(RP2040_PLATFORM)
|
||||
File f = _fs->open(fname, "w");
|
||||
#else
|
||||
File f = _fs->open(fname, "w", true);
|
||||
#endif
|
||||
if (!f) return;
|
||||
// Write hex prefix entries
|
||||
for (int i = 0; i < MAX_BLACKLIST_ENTRIES; i++) {
|
||||
if (_chan_blacklist[i].len == 0) continue;
|
||||
char hex[MAX_PATH_PREFIX_LEN * 2 + 2];
|
||||
mesh::Utils::toHex(hex, _chan_blacklist[i].prefix, _chan_blacklist[i].len);
|
||||
f.println(hex);
|
||||
}
|
||||
// Write #channel_name entries
|
||||
for (int i = 0; i < _num_chan_name_filters; i++) {
|
||||
f.println(_chan_name_filters[i].name);
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
void MyMesh::formatChanBlacklist(char* reply) {
|
||||
char* dp = reply;
|
||||
char* end = reply + MAX_PACKET_PAYLOAD - 6; // leave room for null + safety
|
||||
int count = 0;
|
||||
// Format hex prefix entries
|
||||
for (int i = 0; i < MAX_BLACKLIST_ENTRIES; i++) {
|
||||
if (_chan_blacklist[i].len == 0) continue;
|
||||
if (dp + _chan_blacklist[i].len * 2 + 1 >= end) break;
|
||||
if (count > 0) *dp++ = '\n';
|
||||
mesh::Utils::toHex(dp, _chan_blacklist[i].prefix, _chan_blacklist[i].len);
|
||||
dp += _chan_blacklist[i].len * 2;
|
||||
count++;
|
||||
}
|
||||
// Format #channel_name entries
|
||||
for (int i = 0; i < _num_chan_name_filters; i++) {
|
||||
int len = strlen(_chan_name_filters[i].name);
|
||||
if (dp + len + 1 >= end) break;
|
||||
if (count > 0) *dp++ = '\n';
|
||||
memcpy(dp, _chan_name_filters[i].name, len);
|
||||
dp += len;
|
||||
count++;
|
||||
}
|
||||
if (count == 0) {
|
||||
strcpy(reply, "-none-");
|
||||
} else {
|
||||
*dp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
|
||||
// just try to determine region for packet (apply later in allowPacketForward())
|
||||
if (pkt->getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
|
|
@ -558,6 +850,19 @@ bool MyMesh::filterRecvFloodPacket(mesh::Packet* pkt) {
|
|||
} else {
|
||||
recv_pkt_region = NULL;
|
||||
}
|
||||
|
||||
// Drop packets whose path contains a blacklisted node prefix
|
||||
if (isPathBlacklisted(pkt)) {
|
||||
MESH_DEBUG_PRINTLN("filterRecvFloodPacket: path prefix blacklisted, dropping!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Drop group-channel packets whose channel hash is blacklisted
|
||||
if (isChanBlacklisted(pkt)) {
|
||||
MESH_DEBUG_PRINTLN("filterRecvFloodPacket: channel hash blacklisted, dropping!");
|
||||
return true;
|
||||
}
|
||||
|
||||
// do normal processing
|
||||
return false;
|
||||
}
|
||||
|
|
@ -864,6 +1169,11 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
|||
_logging = false;
|
||||
region_load_active = false;
|
||||
|
||||
memset(_path_blacklist, 0, sizeof(_path_blacklist));
|
||||
memset(_chan_blacklist, 0, sizeof(_chan_blacklist));
|
||||
memset(_chan_name_filters, 0, sizeof(_chan_name_filters));
|
||||
_num_chan_name_filters = 0;
|
||||
|
||||
#if MAX_NEIGHBOURS
|
||||
memset(neighbours, 0, sizeof(neighbours));
|
||||
#endif
|
||||
|
|
@ -926,6 +1236,8 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
|||
acl.load(_fs, self_id);
|
||||
// TODO: key_store.begin();
|
||||
region_map.load(_fs);
|
||||
loadBlacklist(PATH_BLACKLIST_FILE, _path_blacklist);
|
||||
loadChanBlacklist(CHAN_BLACKLIST_FILE);
|
||||
|
||||
// establish default-scope
|
||||
{
|
||||
|
|
@ -1251,6 +1563,93 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
|
|||
sendNodeDiscoverReq();
|
||||
strcpy(reply, "OK - Discover sent");
|
||||
}
|
||||
} else if (memcmp(command, "blacklist ", 10) == 0) {
|
||||
// Commands:
|
||||
// blacklist path list
|
||||
// blacklist path add <hex>[,<hex>,...] (each hex = 2-8 even chars → 1-4 bytes)
|
||||
// blacklist path rem <hex>[,<hex>,...]
|
||||
// blacklist path clear
|
||||
// blacklist chan list
|
||||
// blacklist chan add <hex|#name>[,<hex|#name>,...]
|
||||
// blacklist chan rem <hex|#name>[,<hex|#name>,...]
|
||||
// blacklist chan clear
|
||||
const char* parts[5];
|
||||
int n = mesh::Utils::parseTextParts(command, parts, 5, ' ');
|
||||
|
||||
BlacklistEntry* list = NULL;
|
||||
const char* list_file = NULL;
|
||||
bool is_chan = false;
|
||||
if (n >= 2 && strcmp(parts[1], "path") == 0) {
|
||||
list = _path_blacklist; list_file = PATH_BLACKLIST_FILE;
|
||||
} else if (n >= 2 && strcmp(parts[1], "chan") == 0) {
|
||||
list = _chan_blacklist; list_file = CHAN_BLACKLIST_FILE;
|
||||
is_chan = true;
|
||||
}
|
||||
|
||||
if (list && n >= 3 && strcmp(parts[2], "list") == 0) {
|
||||
if (is_chan) {
|
||||
formatChanBlacklist(reply);
|
||||
} else {
|
||||
formatBlacklist(list, reply);
|
||||
}
|
||||
} else if (list && n >= 3 && strcmp(parts[2], "clear") == 0) {
|
||||
memset(list, 0, sizeof(BlacklistEntry) * MAX_BLACKLIST_ENTRIES);
|
||||
if (is_chan) {
|
||||
_num_chan_name_filters = 0;
|
||||
memset(_chan_name_filters, 0, sizeof(_chan_name_filters));
|
||||
saveChanBlacklist(list_file);
|
||||
} else {
|
||||
saveBlacklist(list_file, list);
|
||||
}
|
||||
strcpy(reply, "OK");
|
||||
} else if (list && n >= 4 && (strcmp(parts[2], "add") == 0 || strcmp(parts[2], "rem") == 0)) {
|
||||
bool is_add = (parts[2][0] == 'a');
|
||||
// parts[3] may be a comma-separated list of hex entries or #channel_name entries
|
||||
char tokens[MAX_PATH_PREFIX_LEN * 2 * MAX_BLACKLIST_ENTRIES + MAX_BLACKLIST_ENTRIES + 2];
|
||||
strncpy(tokens, parts[3], sizeof(tokens) - 1);
|
||||
tokens[sizeof(tokens) - 1] = 0;
|
||||
|
||||
const char* tok_parts[MAX_BLACKLIST_ENTRIES];
|
||||
int tok_n = mesh::Utils::parseTextParts(tokens, tok_parts, MAX_BLACKLIST_ENTRIES, ',');
|
||||
|
||||
bool any_ok = false, any_err = false;
|
||||
for (int t = 0; t < tok_n; t++) {
|
||||
if (is_chan && tok_parts[t][0] == '#') {
|
||||
// #channel_name entry
|
||||
bool ok = is_add ? addChanNameFilter(tok_parts[t])
|
||||
: removeChanNameFilter(tok_parts[t]);
|
||||
if (ok) any_ok = true; else any_err = true;
|
||||
} else {
|
||||
int hex_str_len = strlen(tok_parts[t]);
|
||||
if (hex_str_len < 2 || hex_str_len > MAX_PATH_PREFIX_LEN * 2 || (hex_str_len % 2) != 0) {
|
||||
any_err = true; continue;
|
||||
}
|
||||
uint8_t prefix[MAX_PATH_PREFIX_LEN];
|
||||
int byte_len = hex_str_len / 2;
|
||||
if (!mesh::Utils::fromHex(prefix, byte_len, tok_parts[t])) {
|
||||
any_err = true; continue;
|
||||
}
|
||||
bool ok = is_add ? addToBlacklist(list, prefix, (uint8_t)byte_len)
|
||||
: removeFromBlacklist(list, prefix, (uint8_t)byte_len);
|
||||
if (ok) any_ok = true; else any_err = true;
|
||||
}
|
||||
}
|
||||
|
||||
// auto-save on any successful mutation
|
||||
if (any_ok) {
|
||||
if (is_chan) {
|
||||
saveChanBlacklist(list_file);
|
||||
} else {
|
||||
saveBlacklist(list_file, list);
|
||||
}
|
||||
}
|
||||
|
||||
if (any_ok && !any_err) strcpy(reply, "OK");
|
||||
else if (any_ok && any_err) strcpy(reply, "OK (partial)");
|
||||
else strcpy(reply, is_add ? "Err - list full or bad input" : "Err - not found or bad input");
|
||||
} else {
|
||||
strcpy(reply, "Err - usage: blacklist <path|chan> <list|add|rem|clear> [hex|#name[,...]]");
|
||||
}
|
||||
} else{
|
||||
_cli.handleCommand(sender_timestamp, command, reply); // common CLI commands
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,21 @@ struct RepeaterStats {
|
|||
#define MAX_CLIENTS 32
|
||||
#endif
|
||||
|
||||
#define MAX_PATH_PREFIX_LEN 4
|
||||
#define MAX_BLACKLIST_ENTRIES 16
|
||||
#define MAX_CHAN_NAME_FILTERS 8
|
||||
|
||||
struct BlacklistEntry {
|
||||
uint8_t len; // 0 = empty slot
|
||||
uint8_t prefix[MAX_PATH_PREFIX_LEN];
|
||||
};
|
||||
|
||||
struct ChanNameFilter {
|
||||
uint8_t hash[PATH_HASH_SIZE];
|
||||
uint8_t secret[PUB_KEY_SIZE];
|
||||
char name[32];
|
||||
};
|
||||
|
||||
struct NeighbourInfo {
|
||||
mesh::Identity id;
|
||||
uint32_t advert_timestamp;
|
||||
|
|
@ -103,6 +118,10 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
|
|||
unsigned long pending_discover_until;
|
||||
bool region_load_active;
|
||||
unsigned long dirty_contacts_expiry;
|
||||
BlacklistEntry _path_blacklist[MAX_BLACKLIST_ENTRIES];
|
||||
BlacklistEntry _chan_blacklist[MAX_BLACKLIST_ENTRIES];
|
||||
ChanNameFilter _chan_name_filters[MAX_CHAN_NAME_FILTERS];
|
||||
int _num_chan_name_filters;
|
||||
#if MAX_NEIGHBOURS
|
||||
NeighbourInfo neighbours[MAX_NEIGHBOURS];
|
||||
#endif
|
||||
|
|
@ -130,6 +149,20 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
|
|||
File openAppend(const char* fname);
|
||||
bool isLooped(const mesh::Packet* packet, const uint8_t max_counters[]);
|
||||
|
||||
bool isPathBlacklisted(const mesh::Packet* packet) const;
|
||||
bool isChanBlacklisted(const mesh::Packet* packet) const;
|
||||
void loadBlacklist(const char* fname, BlacklistEntry* list);
|
||||
void saveBlacklist(const char* fname, const BlacklistEntry* list);
|
||||
bool addToBlacklist(BlacklistEntry* list, const uint8_t* prefix, uint8_t len);
|
||||
bool removeFromBlacklist(BlacklistEntry* list, const uint8_t* prefix, uint8_t len);
|
||||
void formatBlacklist(const BlacklistEntry* list, char* reply);
|
||||
void deriveChanNameFilter(ChanNameFilter& entry, const char* name);
|
||||
bool addChanNameFilter(const char* name);
|
||||
bool removeChanNameFilter(const char* name);
|
||||
void loadChanBlacklist(const char* fname);
|
||||
void saveChanBlacklist(const char* fname);
|
||||
void formatChanBlacklist(char* reply);
|
||||
|
||||
protected:
|
||||
float getAirtimeBudgetFactor() const override {
|
||||
return _prefs.airtime_factor;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue