temp sync broken

This commit is contained in:
2025-12-30 08:04:26 +01:00
parent 31dda62474
commit 3b2ec32532
27 changed files with 1339 additions and 589 deletions

View File

@@ -21,12 +21,12 @@
// requires at least a 256 byte data
void processFrame (const FrameStruct *frame) {
void processFrame (FrameStruct *frame) {
printFrameHeader (frame);
if (frame->header & PAYLOAD_VERSION_3) { // more than the version 0
MESH_LOGW (TAG, "Frame too new, got version %d instead of 0", (frame->header & PAYLOAD_VERSION_3) >> 6);
}
unsigned char frameType = frame->header & PAYLOAD_TYPE_MASK;
unsigned char index = 0;
@@ -67,12 +67,15 @@ void processFrame (const FrameStruct *frame) {
} else if (frameType == PAYLOAD_TYPE_MULTIPART) {
} else if (frameType == PAYLOAD_TYPE_CONTROL) {
decodeControlFrame (frame);
if (frame->path.pathLen == 0) {
decodeControlFrame (frame);
}
frame->header = 0xFF;
} else if (frameType == PAYLOAD_TYPE_RAW_CUSTOM) {
// not implemented
} else {
stats.packetsReceivedCount--;
}
MESH_LOGD(TAG, "Processed frame");
MESH_LOGD (TAG, "Processed frame");
}

View File

@@ -11,6 +11,6 @@
#include <ctype.h>
#include "stdio.h"
void processFrame (const FrameStruct * frame);
void processFrame (FrameStruct *frame);
#endif

View File

@@ -381,20 +381,39 @@ void sendFrame (const FrameStruct *frame) {
*/
void retransmitFrame (FrameStruct *frame) {
MESH_LOGD (TAG, "Going to check ReTx");
if (frame->header & ROUTE_TYPE_FLOOD || frame->header & ROUTE_TYPE_TRANSPORT_FLOOD) {
MESH_LOGD (TAG, "Header is flood");
if (frame->header != DONT_RETRANSMIT_HEADER && frame->path.pathLen + 1 < MAX_FLOOD_TTL) {
MESH_LOGD (TAG, "Writing pubkey");
/* -------- FLOOD -------- */
if (frame->header & ROUTE_TYPE_FLOOD ||
frame->header & ROUTE_TYPE_TRANSPORT_FLOOD) {
if (frame->header != DONT_RETRANSMIT_HEADER &&
frame->path.pathLen + 1 < MAX_FLOOD_TTL) {
// append self to END of path
frame->path.path[frame->path.pathLen++] = persistent.pubkey[0];
MESH_LOGD (TAG, "Flooding");
vTaskDelay (10);
LoRaTransmit (frame); // TODO check if correct
MESH_LOGD (TAG, "Flooded");
LoRaTransmit (frame);
}
}
if (frame->header & ROUTE_TYPE_DIRECT || frame->header & ROUTE_TYPE_TRANSPORT_DIRECT) {
/* -------- DIRECT -------- */
if (frame->header & ROUTE_TYPE_DIRECT ||
frame->header & ROUTE_TYPE_TRANSPORT_DIRECT) {
// are we the next hop?
if (frame->path.pathLen > 0 &&
frame->path.path[0] == persistent.pubkey[0]) {
// remove self from START of path
frame->path.pathLen--;
memmove (frame->path.path,
frame->path.path + 1,
frame->path.pathLen);
// forward only if there's another hop
if (frame->path.pathLen > 0) {
LoRaTransmit (frame);
}
}
}
}

View File

@@ -12,7 +12,7 @@
#define HMAC_SIZE 2 // meshcore size
#define MAX_FLOOD_TTL 64
int ReadFrame(FrameStruct *frame, int8_t *rssiPacket, int8_t *snrPacket, int8_t *rawSnr);
int ReadFrame (FrameStruct *frame, int8_t *rssiPacket, int8_t *snrPacket, int8_t *rawSnr);
void LoRaTransmit (const FrameStruct *frame);
@@ -22,10 +22,10 @@ FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen);
void sendFrame (const FrameStruct * frame);
*/
void printFrameHeader (const FrameStruct * frame) ;
void printFrameHeader (const FrameStruct *frame);
//CALL LAST, PATH GETS MODIFIED
void retransmitFrame (FrameStruct * frame) ;
// CALL LAST, PATH GETS MODIFIED
void retransmitFrame (FrameStruct *frame);
// Verify MAC + Decrypt

View File

@@ -5,10 +5,10 @@
void sendAdvert (uint8_t shouldFlood);
void decodeAdvertisement (const FrameStruct * frame);
void decodeAdvertisement (const FrameStruct *frame);
void printAdvertisement (const AdvertisementPayload * advert);
void printAdvertisement (const AdvertisementPayload *advert);
void saveAdvert(const AdvertisementPayload * advert);
void saveAdvert (const AdvertisementPayload *advert);
#endif

View File

@@ -105,10 +105,10 @@ void printAnonRequest (const AnonymousRequestPayload *req, int isRoomServer) {
printf (" sync timestamp: %u\n", syncTimestamp);
}
// remaining bytes = password
if (index < req->payloadLen) {
uint8_t passwordLen = req->payloadLen - index;
uint8_t passwordLen = req->payloadLen - index;
if (passwordLen > 16)
passwordLen = 16;
passwordLen = strnlen (&(req->payload[index]), passwordLen);
@@ -175,8 +175,10 @@ void decodeAnonReq (const FrameStruct *frame) {
printAnonRequest (&anonReq, persistent.nodeType == NODE_TYPE_ROOM_SERVER);
uint8_t passwordLen = anonReq.payloadLen - index2;
if (passwordLen > 16)
if (passwordLen > 16) {
passwordLen = 16;
}
passwordLen = strnlen (&(anonReq.payload[index2]), passwordLen);
MESH_LOGI (TAG, "Password len is %d.", passwordLen);
@@ -206,5 +208,9 @@ void decodeAnonReq (const FrameStruct *frame) {
resp.data[index3++] = (randOut >> 24) & 0xFF;
resp.data[index3++] = FIRMWARE_VER_LEVEL;
resp.dataLen = index3;
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_FLOOD ||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
sendPathBack (foundNode, &(frame->path));
}
sendEncryptedResponse (foundNode, &resp);
}

View File

@@ -4,7 +4,7 @@
#include "meshcore/packetstructs.h"
#include "lib/config.h"
void decodeAnonReq (const FrameStruct * frame);
void decodeAnonReq (const FrameStruct *frame);
void sendAnonymousRequest (const NodeEntry *targetNode, const uint8_t *password, uint32_t sync);

View File

@@ -7,6 +7,8 @@
#include "util/hexdump.h"
#include "util/log.h"
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#define TAG "Control"
@@ -41,6 +43,7 @@ void sendDiscoverRequest (const DiscoverRequestPayload *discReq) {
void sendDiscoverResponse (const DiscoverResponsePayload *discResp) {
FrameStruct frame;
frame.header = ROUTE_TYPE_DIRECT | PAYLOAD_TYPE_CONTROL | PAYLOAD_VERSION_0;
frame.path.pathLen = 0;
uint8_t offset = 0;
@@ -89,7 +92,7 @@ void printDiscoverResponse (const DiscoverResponsePayload *p) {
printf ("\n");
}
void decodeControlFrame (const FrameStruct * frame) {
void decodeControlFrame (const FrameStruct *frame) {
uint8_t index = 0;
uint8_t type = frame->payload[index] & 0xF0;
if (type == CONTROL_DATA_FLAG_TYPE_NODE_DISCOVER_REQ) {
@@ -110,7 +113,7 @@ void decodeControlFrame (const FrameStruct * frame) {
discReq.since |= frame->payload[index++] << 24;
}
printDiscoverRequest (&discReq);
if ((discReq.typeFilter >> 2) & persistent.nodeType) {
if ((discReq.typeFilter >> 1) & persistent.nodeType) {
DiscoverResponsePayload discResp;
discResp.tag = discReq.tag;
@@ -119,8 +122,10 @@ void decodeControlFrame (const FrameStruct * frame) {
memcpy (discResp.pubkey, persistent.pubkey, discResp.pubkeyLen);
discResp.snr = stats.lastSNR; // hopefully the correct one
MESH_LOGD (TAG, "Replying to a discover request with tag %d", discResp.tag);
sendDiscoverResponse (&discResp);
MESH_LOGD(TAG, "Replying to a discover request with tag %d", discResp.tag);
printDiscoverResponse (&discResp);
}
} else if (type == CONTROL_DATA_FLAG_DISCOVER_RESP) {

View File

@@ -3,14 +3,14 @@
#include "meshcore/packetstructs.h"
void sendDiscoverRequest(const DiscoverRequestPayload *discReq);
void sendDiscoverRequest (const DiscoverRequestPayload *discReq);
void sendDiscoverResponse(const DiscoverResponsePayload *discResp);
void sendDiscoverResponse (const DiscoverResponsePayload *discResp);
void printDiscoverRequest(const DiscoverRequestPayload *p);
void printDiscoverRequest (const DiscoverRequestPayload *p);
void printDiscoverResponse(const DiscoverResponsePayload *p);
void printDiscoverResponse (const DiscoverResponsePayload *p);
void decodeControlFrame(const FrameStruct * frame);
void decodeControlFrame (const FrameStruct *frame);
#endif

View File

@@ -2,5 +2,4 @@
#define CUSTOM_HEADER
#endif

View File

@@ -2,23 +2,27 @@
#include "lib/telemetry/telemetry.h"
#include "meshcore/meshframing.h"
#include "meshcore/packets/ack.h"
#include "meshcore/packets/advert.h"
#include "meshcore/packetstructs.h"
#include "meshcore/stats.h"
#include "util/hexdump.h"
#include "util/log.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "encrypted.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lib/adc/temperature.h"
#include "lib/rtc/rtc.h"
#include "sx1262.h"
#define TICKS_TO_MS(xTicks) (((uint32_t)(xTicks)*1000U) / (uint32_t)configTICK_RATE_HZ)
#define TAG "EncryptedMessage"
void sendEncryptedFrame (NodeEntry *targetNode, uint8_t payloadType, const uint8_t *plain, size_t plainLen) {
void sendEncryptedFrame (const NodeEntry *targetNode, uint8_t payloadType, const uint8_t *plain, size_t plainLen) {
FrameStruct frame;
uint8_t offset = 0;
@@ -52,7 +56,7 @@ void sendEncryptedFrame (NodeEntry *targetNode, uint8_t payloadType, const uint8
LoRaTransmit (&frame);
}
void sendEncryptedTextMessage (NodeEntry *targetNode, const PlainTextMessagePayload *msg) {
void sendEncryptedTextMessage (const NodeEntry *targetNode, const PlainTextMessagePayload *msg) {
if (targetNode == NULL) {
MESH_LOGW (TAG, "Node is null");
return;
@@ -72,15 +76,16 @@ void sendEncryptedTextMessage (NodeEntry *targetNode, const PlainTextMessagePayl
buf[index++] = (msg->textType << 2) | (msg->attempt & 0x03);
memcpy (&buf[index], msg->message, msgLen);
index += msgLen;
sendEncryptedFrame (
targetNode,
PAYLOAD_TYPE_TXT_MSG,
buf,
index + msgLen);
index);
}
void sendEncryptedResponse (NodeEntry *targetNode, const Response *resp) {
void sendEncryptedResponse (const NodeEntry *targetNode, const Response *resp) {
uint8_t buf[256];
uint8_t index = 0;
@@ -99,7 +104,7 @@ void sendEncryptedResponse (NodeEntry *targetNode, const Response *resp) {
index);
}
void sendEncryptedRequest (NodeEntry *targetNode, const Request *req) {
void sendEncryptedRequest (const NodeEntry *targetNode, const Request *req) {
uint8_t buf[256];
uint8_t index = 0;
@@ -119,7 +124,7 @@ void sendEncryptedRequest (NodeEntry *targetNode, const Request *req) {
index);
}
void sendEncryptedPathPayload (NodeEntry *targetNode, const ReturnedPathPayload *path) {
void sendEncryptedPathPayload (const NodeEntry *targetNode, const ReturnedPathPayload *path) {
uint8_t buf[256];
uint8_t index = 0;
@@ -127,9 +132,17 @@ void sendEncryptedPathPayload (NodeEntry *targetNode, const ReturnedPathPayload
memcpy (&buf[index], path->path.path, path->path.pathLen);
index += path->path.pathLen;
buf[index++] = path->extra.type;
memcpy (&buf[index], path->extra.data,
path->extra.dataLen);
if (path->extra.dataLen > 0) {
buf[index++] = path->extra.type;
memcpy (&buf[index], path->extra.data, path->extra.dataLen);
} else {
buf[index++] = 0xFF;
uint32_t timestamp = RTC_GetCounter();
buf[index++] = timestamp;
buf[index++] = timestamp >> 8;
buf[index++] = timestamp >> 16;
buf[index++] = timestamp >> 24;
}
sendEncryptedFrame (
targetNode,
@@ -188,6 +201,8 @@ void printEncryptedPayload (const EncryptedPayloadStruct *enc) {
void decodeEncryptedPayload (const FrameStruct *frame) {
EncryptedPayloadStruct enc;
memset (&enc, 0, sizeof (enc));
enc.path = &(frame->path);
enc.origFrame = frame;
enc.type = frame->header & PAYLOAD_TYPE_MASK;
unsigned char index = 0;
@@ -206,11 +221,11 @@ void decodeEncryptedPayload (const FrameStruct *frame) {
enc.remNode = remNode;
if (remNode == NULL) {
MESH_LOGW (TAG, "Node not in DB");
return;
}
remNode->last_seen_lt = RTC_GetCounter();
MESH_LOGI (TAG, "Found node with index %d", remNode - persistent.contacts);
@@ -228,6 +243,17 @@ void decodeEncryptedPayload (const FrameStruct *frame) {
}
}
void sendPathBack (const NodeEntry *node, const Path *path) {
ReturnedPathPayload retPath;
retPath.extra.dataLen = 0; // redo to send the resp in path
retPath.extra.type = 0xFF;
retPath.path.pathLen = path->pathLen;
memcpy (retPath.path.path, path->path, path->pathLen);
sendEncryptedPathPayload (node, &retPath);
}
void parseEncryptedPayload (const EncryptedPayloadStruct *enc) {
// printEncryptedPayload(&enc);
@@ -242,7 +268,6 @@ void parseEncryptedPayload (const EncryptedPayloadStruct *enc) {
uint8_t index = 0;
if (enc->type == PAYLOAD_TYPE_PATH) {
ReturnedPathPayload retPath;
retPath.path.pathLen = enc->payload[index++];
if (retPath.path.pathLen > 64) {
@@ -255,16 +280,26 @@ void parseEncryptedPayload (const EncryptedPayloadStruct *enc) {
retPath.extra.dataLen = enc->payloadLen - index;
memcpy (retPath.extra.data, &(enc->payload[index]), retPath.extra.dataLen);
if ((enc->origFrame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_FLOOD ||
(enc->origFrame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
sendPathBack (enc->remNode, enc->path);
}
} else if (enc->type == PAYLOAD_TYPE_REQ) {
Request req;
req.timestamp = enc->payload[index++];
req.timestamp |= enc->payload[index++] << 8;
req.timestamp |= enc->payload[index++] << 16;
req.timestamp |= enc->payload[index++] << 24;
enc->remNode->last_seen_rt = req.timestamp;
req.requestType = enc->payload[index++];
req.dataLen = enc->payloadLen - index;
memcpy (req.data, &(enc->payload[index]), req.dataLen);
printRequest (&req);
if ((enc->origFrame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_FLOOD ||
(enc->origFrame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
sendPathBack (enc->remNode, enc->path);
}
switch (req.requestType) {
case REQUEST_GET_STATS: {
Response resp;
@@ -281,6 +316,7 @@ void parseEncryptedPayload (const EncryptedPayloadStruct *enc) {
case REQUEST_GET_TELEMETRY_DATA: {
Response resp;
resp.tag = req.timestamp;
enc->remNode->last_seen_rt = req.timestamp;
uint8_t index2 = 0;
resp.data[index2++] = TELEM_CHANNEL_SELF;
resp.data[index2++] = LPP_TEMPERATURE;
@@ -351,9 +387,403 @@ void parseEncryptedPayload (const EncryptedPayloadStruct *enc) {
plaintext.timestamp |= enc->payload[index++] << 8;
plaintext.timestamp |= enc->payload[index++] << 16;
plaintext.timestamp |= enc->payload[index++] << 24;
enc->remNode->last_seen_rt = plaintext.timestamp;
plaintext.attempt = enc->payload[index] & 0x03;
plaintext.textType = enc->payload[index++] >> 2;
memcpy (plaintext.message, &(enc->payload[index]), enc->payloadLen - index);
printPlainTextMessage (&plaintext);
if ((enc->origFrame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_FLOOD ||
(enc->origFrame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
sendPathBack (enc->remNode, enc->path);
}
switch (plaintext.textType) {
case TXT_TYPE_PLAIN:
printf ("Plaintext message from %s, attempt %d, timestamp %d: %s", enc->remNode->name, plaintext.attempt, plaintext.timestamp, plaintext.message);
break;
case TXT_TYPE_CLI_DATA:
if (enc->remNode->authenticated) {
processCommand (plaintext.message, enc->remNode);
}
break;
case TXT_TYPE_SIGNED_PLAIN: {
uint8_t senderPubKeyPrefix[4];
memcpy (senderPubKeyPrefix, plaintext.message, sizeof (senderPubKeyPrefix));
NodeEntry *senderNode = getNodePrefix (senderPubKeyPrefix);
printf ("Plaintext message from server %s, sender is %s, attempt %d, timestamp %d: %s", enc->remNode->name, senderNode->name, plaintext.attempt, plaintext.timestamp, &(plaintext.message[4]));
break;
}
default:
MESH_LOGW (TAG, "Unknown text type: %d", plaintext.textType);
break;
}
}
}
}
#define STR_EQ_LIT(s, lit) (memcmp ((s), (lit), sizeof (lit) - 1) == 0)
void processCommand (char *cmd, NodeEntry *remNode) {
PlainTextMessagePayload replyPayload;
replyPayload.timestamp = RTC_GetCounter();
replyPayload.attempt = 0;
replyPayload.textType = TXT_TYPE_CLI_DATA;
uint8_t *reply = replyPayload.message;
reply[0] = 0;
while (*cmd == ' ') cmd++; // skip leading spaces
// Optional CLI prefix (xx|) for companion radio
if (strlen (cmd) > 4 && cmd[2] == '|') {
memcpy (reply, cmd, 3);
reply += 3;
cmd += 3;
}
/* ---------------- System ---------------- */
if (STR_EQ_LIT (cmd, "reboot")) {
NVIC_SystemReset();
} else if (STR_EQ_LIT (cmd, "advert")) {
sendAdvert (1); // 1500ms delay in reference
strcpy ((char *)reply, "OK - Advert sent");
} else if (STR_EQ_LIT (cmd, "clear stats")) {
memset (&stats, 0, sizeof (stats));
strcpy ((char *)reply, "(OK - stats reset)");
}
else if (STR_EQ_LIT (cmd, "ver")) {
sprintf ((char *)reply, "%s (Build: %s)", VERSION, __DATE__);
}
else if (STR_EQ_LIT (cmd, "board")) {
sprintf ((char *)reply, "%s", BOARD);
}
/* ---------------- Clock ---------------- */
else if (STR_EQ_LIT (cmd, "clock")) {
RTC_Get();
sprintf ((char *)reply, "%02d:%02d:%02d - %d/%d/%d UTC",
calendar.hour, calendar.min, calendar.sec,
calendar.w_date, calendar.w_month, calendar.w_year);
} else if (STR_EQ_LIT (cmd, "time ")) {
uint32_t secs = atoi (&cmd[5]);
uint32_t curr = RTC_GetCounter();
if (secs > curr) {
RTC_SetCounter (secs);
RTC_Get();
sprintf ((char *)reply, "OK - clock set: %02d:%02d:%02d - %d/%d/%d UTC",
calendar.hour, calendar.min, calendar.sec,
calendar.w_date, calendar.w_month, calendar.w_year);
} else {
strcpy ((char *)reply, "(ERR: clock cannot go backwards)");
}
} else if (STR_EQ_LIT (cmd, "clock sync")) {
uint32_t curr = RTC_GetCounter();
uint32_t sender = replyPayload.timestamp;
if (sender > curr) {
RTC_SetCounter (sender + 1);
RTC_Get();
sprintf ((char *)reply, "OK - clock set: %02d:%02d:%02d - %d/%d/%d UTC",
calendar.hour, calendar.min, calendar.sec,
calendar.w_date, calendar.w_month, calendar.w_year);
} else {
strcpy ((char *)reply, "ERR: clock cannot go backwards");
}
}
/* ---------------- Neighbors ---------------- */
else if (STR_EQ_LIT (cmd, "neighbors")) {
Callbacks_FormatNeighborsReply ((char *)reply);
} else if (STR_EQ_LIT (cmd, "neighbor.remove ")) {
const char *hex = cmd + 16;
uint8_t pubkey[PUB_KEY_SIZE];
int len = strlen (hex) / 2;
if (mesh_fromHex (pubkey, len, hex)) {
Callbacks_RemoveNeighbor (pubkey, len);
strcpy ((char *)reply, "OK");
} else {
strcpy ((char *)reply, "ERR: bad pubkey");
}
}
/* ---------------- Radio / Temp ---------------- */
else if (STR_EQ_LIT (cmd, "tempradio ")) {
char tmp[64];
strcpy (tmp, &cmd[10]);
const char *parts[5];
int num = mesh_ParseTextParts (tmp, parts, 5); // assume helper
float freq = num > 0 ? strtof (parts[0], NULL) : 0.0f;
float bw = num > 1 ? strtof (parts[1], NULL) : 0.0f;
uint8_t sf = num > 2 ? atoi (parts[2]) : 0;
uint8_t cr = num > 3 ? atoi (parts[3]) : 0;
int timeout_mins = num > 4 ? atoi (parts[4]) : 0;
if (freq >= 300.0f && freq <= 2500.0f && bw >= 7.0f && bw <= 500.0f &&
sf >= 5 && sf <= 12 && cr >= 5 && cr <= 8 && timeout_mins > 0) {
Callbacks_ApplyTempRadioParams (freq, bw, sf, cr, timeout_mins);
LoraApply();
sprintf ((char *)reply, "OK - temp params for %d mins", timeout_mins);
} else {
strcpy ((char *)reply, "Error, invalid params");
}
}
/* ---------------- Password ---------------- */
else if (STR_EQ_LIT (cmd, "password ")) {
strncpy (persistent.password, &cmd[9], sizeof (persistent.password));
// savePrefs(); TODO add this
sprintf ((char *)reply, "password now: %s", persistent.password);
}
/* ---------------- GET / SET Config ---------------- */
else if (STR_EQ_LIT (cmd, "get ")) {
const char *config = &cmd[4];
if (memcmp (config, "af", 2) == 0) {
sprintf (reply, "> %f", persistent.airtimeFactor);
} else if (memcmp (config, "int.thresh", 10) == 0) {
sprintf (reply, "> %d", (uint32_t)_prefs->interference_threshold);
} else if (memcmp (config, "agc.reset.interval", 18) == 0) {
sprintf (reply, "> %d", ((uint32_t)_prefs->agc_reset_interval) * 4);
} else if (memcmp (config, "multi.acks", 10) == 0) {
sprintf (reply, "> %d", (uint32_t)_prefs->multi_acks);
} else if (memcmp (config, "allow.read.only", 15) == 0) {
sprintf (reply, "> %s", _prefs->allow_read_only ? "on" : "off");
} else if (memcmp (config, "flood.advert.interval", 21) == 0) {
sprintf (reply, "> %d", (uint32_t)_prefs->flood_advert_interval);
} else if (memcmp (config, "advert.interval", 15) == 0) {
sprintf (reply, "> %d", ((uint32_t)_prefs->advert_interval) * 2);
} else if (memcmp (config, "guest.password", 14) == 0) {
sprintf (reply, "> %s", persistent.guestPassword);
} else if (memcmp (config, "name", 4) == 0) {
sprintf (reply, "> %s", persistent.nodeName);
} else if (memcmp (config, "repeat", 6) == 0) {
sprintf (reply, "> %s", persistent.doRepeat ? "on" : "off");
} else if (memcmp (config, "lat", 3) == 0) {
sprintf (reply, "> %d", persistent.latitude);
} else if (memcmp (config, "lon", 3) == 0) {
sprintf (reply, "> %d", persistent.longitude);
} else if (memcmp (config, "radio", 5) == 0) {
char freq[16], bw[16];
snprintf(freq, sizeof(freq), "%lf", persistent.frequencyInHz / 1000000.0);
snprintf(bw, sizeof(bw), "%lf", loraBwToFloat(persistent.bandwidth));
sprintf (reply, "> %s,%s,%d,%d", freq, bw, persistent.spreadingFactor, persistent.codingRate + 4);
} else if (memcmp (config, "rxdelay", 7) == 0) {
sprintf (reply, "> %s", StrHelper::ftoa (_prefs->rx_delay_base));
} else if (memcmp (config, "txdelay", 7) == 0) {
sprintf (reply, "> %s", StrHelper::ftoa (_prefs->tx_delay_factor));
} else if (memcmp (config, "flood.max", 9) == 0) {
sprintf (reply, "> %d", (uint32_t)_prefs->flood_max);
} else if (memcmp (config, "direct.txdelay", 14) == 0) {
sprintf (reply, "> %s", StrHelper::ftoa (_prefs->direct_tx_delay_factor));
} else if (memcmp (config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) {
sprintf (reply, "> %d", (uint32_t)_prefs->tx_power_dbm);
} else if (memcmp (config, "freq", 4) == 0) {
sprintf (reply, "> %s", StrHelper::ftoa (_prefs->freq));
} else if (memcmp (config, "public.key", 10) == 0) {
strcpy (reply, "> ");
hexdump_compact(persistent.pubkey, sizeof(persistent.pubkey), &(reply[2]), 70);
} else if (memcmp (config, "role", 4) == 0) {
sprintf (reply, "> %s", getStringRole(persistent.nodeType));
} else if (memcmp (config, "adc.multiplier", 14) == 0) {
sprintf (reply, "> %.3f", persistent.adcMultiplier);
} else {
sprintf (reply, "??: %s", config);
}
} else if (STR_EQ_LIT (cmd, "set ")) {
const char *config = &cmd[4];
if (memcmp (config, "af ", 3) == 0) {
persistent.airtimeFactor = atof (&config[3]);
// savePrefs();
strcpy (reply, "OK");
} else if (memcmp (config, "int.thresh ", 11) == 0) {
_prefs->interference_threshold = atoi (&config[11]);
// savePrefs();
strcpy (reply, "OK");
} else if (memcmp (config, "agc.reset.interval ", 19) == 0) {
_prefs->agc_reset_interval = atoi (&config[19]) / 4;
// savePrefs();
sprintf (reply, "OK - interval rounded to %d", ((uint32_t)_prefs->agc_reset_interval) * 4);
} else if (memcmp (config, "multi.acks ", 11) == 0) {
_prefs->multi_acks = atoi (&config[11]);
// savePrefs();
strcpy (reply, "OK");
} else if (memcmp (config, "allow.read.only ", 16) == 0) {
if (memcmp (&config[16], "on", 2) == 0) {
persistent.allowReadOnly = 1;
strcpy (reply, "OK");
} else if (memcmp (&config[16], "off", 3) == 0) {
persistent.allowReadOnly = 0;
strcpy (reply, "OK");
}
//savePrefs();
} else if (memcmp (config, "flood.advert.interval ", 22) == 0) {
int hours = _atoi (&config[22]);
if ((hours > 0 && hours < 3) || (hours > 48)) {
strcpy (reply, "Error: interval range is 3-48 hours");
} else {
_prefs->flood_advert_interval = (uint8_t)hours;
_callbacks->updateFloodAdvertTimer();
savePrefs();
strcpy (reply, "OK");
}
} else if (memcmp (config, "advert.interval ", 16) == 0) {
int mins = _atoi (&config[16]);
if ((mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) || (mins > 240)) {
sprintf (reply, "Error: interval range is %d-240 minutes", MIN_LOCAL_ADVERT_INTERVAL);
} else {
_prefs->advert_interval = (uint8_t)(mins / 2);
_callbacks->updateAdvertTimer();
savePrefs();
strcpy (reply, "OK");
}
} else if (memcmp (config, "guest.password ", 15) == 0) {
strncpy (persistent.guestPassword, &config[15], sizeof (persistent.guestPassword));
// savePrefs();
strcpy (reply, "OK");
} else if (memcmp (config, "name ", 5) == 0) {
strncpy (persistent.nodeName, &config[5], sizeof (persistent.nodeName));
// savePrefs();
strcpy (reply, "OK");
} else if (memcmp (config, "repeat ", 7) == 0) {
if (memcmp (&config[7], "off", 3) == 0) {
persistent.doRepeat = 0;
} else if (memcmp (&config[7], "on", 2) == 0) {
persistent.doRepeat = 1;
}
// savePrefs();
strcpy (reply, persistent.doRepeat ? "OK - repeat is now ON" : "OK - repeat is now OFF");
} else if (memcmp (config, "radio ", 6) == 0) {
strcpy (tmp, &config[6]);
const char *parts[4];
int num = mesh::Utils::parseTextParts (tmp, parts, 4);
float freq = num > 0 ? strtof (parts[0], nullptr) : 0.0f;
float bw = num > 1 ? strtof (parts[1], nullptr) : 0.0f;
uint8_t sf = num > 2 ? atoi (parts[2]) : 0;
uint8_t cr = num > 3 ? atoi (parts[3]) : 0;
if (freq >= 300.0f && freq <= 2500.0f && sf >= 5 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7.0f && bw <= 500.0f) {
_prefs->sf = sf;
_prefs->cr = cr;
_prefs->freq = freq;
_prefs->bw = bw;
_callbacks->savePrefs();
strcpy (reply, "OK - reboot to apply");
} else {
strcpy (reply, "Error, invalid radio params");
}
} else if (memcmp (config, "lat ", 4) == 0) {
double lat = atof (&config[4]);
lat *= 1000000;
persistent.latitude = lat;
// savePrefs();
strcpy (reply, "OK");
} else if (memcmp (config, "lon ", 4) == 0) {
double lon = atof (&config[4]);
lon *= 1000000;
persistent.longitude = lon;
// savePrefs();
strcpy (reply, "OK");
} else if (memcmp (config, "rxdelay ", 8) == 0) {
float db = atof (&config[8]);
if (db >= 0) {
_prefs->rx_delay_base = db;
savePrefs();
strcpy (reply, "OK");
} else {
strcpy (reply, "Error, cannot be negative");
}
} else if (memcmp (config, "txdelay ", 8) == 0) {
float f = atof (&config[8]);
if (f >= 0) {
_prefs->tx_delay_factor = f;
savePrefs();
strcpy (reply, "OK");
} else {
strcpy (reply, "Error, cannot be negative");
}
} else if (memcmp (config, "flood.max ", 10) == 0) {
uint8_t m = atoi (&config[10]);
if (m <= 64) {
_prefs->flood_max = m;
savePrefs();
strcpy (reply, "OK");
} else {
strcpy (reply, "Error, max 64");
}
} else if (memcmp (config, "direct.txdelay ", 15) == 0) {
float f = atof (&config[15]);
if (f >= 0) {
_prefs->direct_tx_delay_factor = f;
savePrefs();
strcpy (reply, "OK");
} else {
strcpy (reply, "Error, cannot be negative");
}
} else if (memcmp (config, "tx ", 3) == 0) {
_prefs->tx_power_dbm = atoi (&config[3]);
savePrefs();
_callbacks->setTxPower (_prefs->tx_power_dbm);
strcpy (reply, "OK");
} else if (memcmp (config, "freq ", 5) == 0) {
double freq = atof (&config[5]);
uint32_t newFreq = mhzToHzLimited (persistent.frequencyInHz);
if (newFreq != 0) {
persistent.frequencyInHz = newFreq;
}
// savePrefs();
strcpy (reply, "OK - reboot to apply");
} else if (memcmp (config, "adc.multiplier ", 15) == 0) {
persistent.adcMultiplier = atof (&config[15]);
if (persistent.adcMultiplier == 0.0f) {
strcpy (reply, "OK - using default board multiplier");
} else {
sprintf (reply, "OK - multiplier set to %.3f", persistent.adcMultiplier);
}
// savePrefs();
} else {
sprintf (reply, "unknown config: %s", config);
}
}
/* ---------------- Stats ---------------- */
else if (STR_EQ_LIT (cmd, "stats-packets")) {
sprintf (reply,
"{\"recv\":%u,\"sent\":%u,\"flood_tx\":%u,\"direct_tx\":%u,\"flood_rx\":%u,\"direct_rx\":%u}",
stats.packetsReceivedCount,
stats.packetsSentCount,
stats.sentFloodCount,
stats.sentDirectCount,
stats.receivedFloodCount,
stats.receivedDirectCount);
} else if (STR_EQ_LIT (cmd, "stats-radio")) {
sprintf (reply,
"{\"noise_floor\":%d,\"last_rssi\":%d,\"last_snr\":%.2f,\"tx_air_secs\":%u,\"rx_air_secs\":%u}",
stats.noiseFloor,
stats.lastRSSI,
stats.lastSNR / 4.0,
stats.totalAirTimeSeconds,
stats.total_rx_air_time_secs);
} else if (STR_EQ_LIT (cmd, "stats-core")) {
stats.totalUpTimeSeconds = RTC_GetCounter() - startupTime;
stats.totalAirTimeSeconds = TICKS_TO_MS (tickAirtime / 1000);
sprintf (reply,
"{\"battery_mv\":%u,\"uptime_secs\":%u,\"errors\":%u,\"queue_len\":%u}",
getVoltage(),
stats.totalUpTimeSeconds,
stats.err_events,
stats.txQueueLength);
}
/* ---------------- Unknown ---------------- */
else {
strcpy ((char *)reply, "Unknown command");
}
sendEncryptedTextMessage (remNode, &replyPayload);
}

View File

@@ -8,18 +8,22 @@
#include <string.h>
void sendEncryptedFrame (NodeEntry *targetNode, uint8_t payloadType, const uint8_t *plain, size_t plainLen);
void sendEncryptedFrame (const NodeEntry *targetNode, uint8_t payloadType, const uint8_t *plain, size_t plainLen);
void sendEncryptedTextMessage (NodeEntry *targetNode, const PlainTextMessagePayload *msg);
void sendEncryptedTextMessage (const NodeEntry *targetNode, const PlainTextMessagePayload *msg);
void sendEncryptedResponse (NodeEntry *targetNode, const Response *resp);
void sendEncryptedResponse (const NodeEntry *targetNode, const Response *resp);
void sendEncryptedRequest (NodeEntry *targetNode, const Request *req);
void sendEncryptedRequest (const NodeEntry *targetNode, const Request *req);
void sendEncryptedPathPayload (NodeEntry *targetNode, const ReturnedPathPayload *path);
void sendEncryptedPathPayload (const NodeEntry *targetNode, const ReturnedPathPayload *path);
void decodeEncryptedPayload (const FrameStruct *frame);
void parseEncryptedPayload (const EncryptedPayloadStruct * enc);
void parseEncryptedPayload (const EncryptedPayloadStruct *enc);
void processCommand(char * cmd, NodeEntry * remNode);
void sendPathBack (const NodeEntry *node, const Path *path);
#endif

View File

@@ -11,7 +11,7 @@
void sendGroupMessage (const GroupTextMessage *msg) {
// Prepare values locally instead of modifying msg
uint8_t channelHash = persistent.aesKeys[msg->keyIndex][0];
Channel *channel = &(persistent.channels[msg->keyIndex]);
uint8_t flags = 0;
int32_t timestamp = RTC_GetCounter();
@@ -19,7 +19,7 @@ void sendGroupMessage (const GroupTextMessage *msg) {
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_GRP_TXT | PAYLOAD_VERSION_0;
frame.path.pathLen = 0;
size_t offset = 0;
frame.payload[offset++] = channelHash;
frame.payload[offset++] = channel->hash;
// Build encryption buffer directly on stack (no extra large buffer)
uint8_t buf[180]; // enough for timestamp + flags + text
@@ -41,10 +41,13 @@ void sendGroupMessage (const GroupTextMessage *msg) {
// Encrypt and MAC directly into frame payload after channelHash
size_t olen = 0;
encrypt_then_mac (&persistent.aesKeys[msg->keyIndex][1], 16, buf, buf_offset, &frame.payload[offset], &olen);
encrypt_then_mac (channel->key, 16, buf, buf_offset, &frame.payload[offset], &olen);
frame.payloadLen = olen + 1; // +1 for channelHash
channel->timestamp = timestamp;
LoRaTransmit (&frame);
}
@@ -70,43 +73,35 @@ void decodeGroupMessage (const FrameStruct *frame) {
unsigned char tmp[184];
unsigned char decrypted = 0;
for (unsigned char i = 0; i < AESKeyCount; i++) {
Channel *channel = NULL;
if (msg.channelHash != persistent.aesKeys[i][0]) {
MESH_LOGW (TAG, "Hash %d does not equal %d", persistent.aesKeys[i][0], msg.channelHash);
uint8_t i = 0;
do {
channel = getChannel (msg.channelHash, i);
if (channel == NULL) {
MESH_LOGW (TAG, "Channel hash %d not found", msg.channelHash);
return;
}
if (mac_then_decrypt (channel->key, 16, frame->payload + index, frame->payloadLen - index, tmp) != 0) {
MESH_LOGW (TAG, "HMAC failed on grouphash key %d", msg.channelHash);
i++;
continue;
} else {
unsigned char plaintextLen = frame->payloadLen - index;
index = 0;
memcpy (&msg.timestamp, tmp + index, 4);
index += 4;
msg.flags = tmp[index++];
memcpy (msg.text, tmp + index, plaintextLen - index);
channel->timestamp = RTC_GetCounter();
printf ("Message from channel %s: %s\n", channel->name, msg.text);
break;
}
MESH_LOGW (TAG, "Hash does equal %d", msg.channelHash);
if (mac_then_decrypt (persistent.aesKeys[i] + 1, 16, frame->payload + index, frame->payloadLen - index, tmp) != 0) {
MESH_LOGW (TAG, "HMAC failed on grouphash key %d not matching %d", persistent.aesKeys[i][0], msg.channelHash);
continue;
}
hexdump ("RxDumpDec", tmp, frame->payloadLen - index);
decrypted = 1;
break;
}
if (!decrypted) {
return;
}
unsigned char plaintextLen = frame->payloadLen - index;
index = 0;
memcpy (&msg.timestamp, tmp + index, 4);
index += 4;
msg.flags = tmp[index++];
memcpy (msg.text, tmp + index, plaintextLen - index);
printGroupMessage (&msg);
}
void printGroupMessage (const GroupTextMessage *msg) {
printf ("Message with channel hash %d, flags %d: %s\n", msg->channelHash,
msg->flags, msg->text);
} while (channel != NULL);
}

View File

@@ -4,12 +4,10 @@
#include "stdint.h"
#include "meshcore/packetstructs.h"
void sendGroupMessage (const GroupTextMessage * msg);
void sendGroupMessage (const GroupTextMessage *msg);
void makeSendGroupMessage (char *txt, uint8_t keyIndex);
void decodeGroupMessage (const FrameStruct * frame);
void printGroupMessage (const GroupTextMessage * msg);
void decodeGroupMessage (const FrameStruct *frame);
#endif

View File

@@ -2,5 +2,4 @@
#define TRACE_HEADER
#endif

View File

@@ -18,9 +18,16 @@
#define PERM_ACL_READ_WRITE 2
#define PERM_ACL_ADMIN 3
#define NODE_ENTRY_FAV_FLAG (1 << 0)
#define MAX_PATH_LEN 64
#define TXT_TYPE_PLAIN 0 // a plain text message
#define TXT_TYPE_CLI_DATA 1 // a CLI command
#define TXT_TYPE_SIGNED_PLAIN 2 // plain text, signed by sender
typedef enum RouteType {
ROUTE_TYPE_TRANSPORT_FLOOD = 0x00,
ROUTE_TYPE_FLOOD = 0x01,
@@ -126,14 +133,14 @@ typedef struct {
int32_t gps_longitude;
Path path;
uint8_t flags;
uint8_t type;
uint8_t authenticated;
uint32_t last_seen_rt; //remote timestamp
uint32_t last_seen_lt; //local timestamp
uint32_t last_seen_rt; // remote timestamp
uint32_t last_seen_lt; // local timestamp
uint32_t sync_timestamp;
} NodeEntry;
@@ -146,6 +153,8 @@ typedef struct EncryptedPayloadStruct {
uint8_t payload[180];
uint8_t type;
NodeEntry *remNode;
const Path *path;
const FrameStruct *origFrame;
} EncryptedPayloadStruct;
typedef enum NodeType {
@@ -229,7 +238,10 @@ typedef struct RepeaterStats {
} RepeaterStats;
typedef struct Channel {
char name[32];
uint8_t key[16];
uint8_t hash;
int32_t timestamp;
} Channel;
#endif