really still wip
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include "meshcore/packets/control.h"
|
||||
#include "meshcore/packets/encrypted.h"
|
||||
#include "meshcore/packets/group.h"
|
||||
#include "meshcore/stats.h"
|
||||
#include "task.h"
|
||||
#include "lib/base64.h"
|
||||
#include "lib/cifra/aes.h"
|
||||
@@ -13,52 +14,54 @@
|
||||
#include "lib/cifra/hmac.h"
|
||||
#include "lib/config.h"
|
||||
#include "meshframing.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
#define TAG "MeshCore"
|
||||
|
||||
// requires at least a 256 byte data
|
||||
|
||||
|
||||
void processFrame (FrameStruct frame) {
|
||||
void processFrame (const FrameStruct *frame) {
|
||||
printFrameHeader (frame);
|
||||
if (frame.header & PAYLOAD_VERSION_3) { // more than the version 0
|
||||
ESP_LOGW (TAG, "Frame too new, got version %d instead of 0", (frame.header & PAYLOAD_VERSION_3) >> 6);
|
||||
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 checkSumBuf[10];
|
||||
AdvertisementPayload advert;
|
||||
GroupTextMessage msg;
|
||||
|
||||
unsigned char frameType = frame.header & PAYLOAD_TYPE_MASK;
|
||||
|
||||
unsigned char frameType = frame->header & PAYLOAD_TYPE_MASK;
|
||||
|
||||
unsigned char index = 0;
|
||||
|
||||
stats.packetsReceivedCount++;
|
||||
|
||||
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_FLOOD ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
stats.receivedFloodCount++;
|
||||
}
|
||||
|
||||
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_DIRECT ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT) {
|
||||
stats.receivedDirectCount++;
|
||||
}
|
||||
|
||||
|
||||
if (frameType == PAYLOAD_TYPE_ANON_REQ) {
|
||||
decodeAnonReq (frame);
|
||||
|
||||
} else if (frameType == PAYLOAD_TYPE_PATH || frameType == PAYLOAD_TYPE_REQ || frameType == PAYLOAD_TYPE_RESPONSE || frameType == PAYLOAD_TYPE_TXT_MSG) {
|
||||
printf (" Typexd: 0x%02X\n", frameType);
|
||||
EncryptedPayloadStruct enc = decodeEncryptedPayload (frame);
|
||||
printf (" Typexdd: 0x%02X\n", enc.type);
|
||||
if (enc.payloadLen > 0) {
|
||||
parseEncryptedPayload (enc);
|
||||
}
|
||||
decodeEncryptedPayload (frame);
|
||||
|
||||
} else if (frameType == PAYLOAD_TYPE_ACK) {
|
||||
memset (checkSumBuf, 0, sizeof (checkSumBuf));
|
||||
base64_encode (frame.payload, 4, checkSumBuf);
|
||||
printf ("Checksum: %s\n", checkSumBuf);
|
||||
} else if (frameType == PAYLOAD_TYPE_ACK) {
|
||||
uint32_t checkSum = frame.payload[index++];
|
||||
checkSum |= frame.payload[index++] << 8;
|
||||
checkSum |= frame.payload[index++] << 16;
|
||||
checkSum |= frame.payload[index++] << 24;
|
||||
uint32_t checkSum = frame->payload[index++];
|
||||
checkSum |= frame->payload[index++] << 8;
|
||||
checkSum |= frame->payload[index++] << 16;
|
||||
checkSum |= frame->payload[index++] << 24;
|
||||
// TODO add checking
|
||||
|
||||
} else if (frameType == PAYLOAD_TYPE_ADVERT) {
|
||||
advert = decodeAdvertisement (frame);
|
||||
printAdvertisement (advert);
|
||||
decodeAdvertisement (frame);
|
||||
} else if (frameType == PAYLOAD_TYPE_GRP_TXT || frameType == PAYLOAD_TYPE_GRP_DATA) {
|
||||
msg = decodeGroupMessage (frame);
|
||||
printGroupMessage (msg);
|
||||
decodeGroupMessage (frame);
|
||||
} else if (frameType == PAYLOAD_TYPE_TRACE) {
|
||||
|
||||
} else if (frameType == PAYLOAD_TYPE_MULTIPART) {
|
||||
@@ -68,7 +71,8 @@ void processFrame (FrameStruct frame) {
|
||||
|
||||
} else if (frameType == PAYLOAD_TYPE_RAW_CUSTOM) {
|
||||
// not implemented
|
||||
} else {
|
||||
stats.packetsReceivedCount--;
|
||||
}
|
||||
|
||||
retransmitFrame (frame);
|
||||
MESH_LOGD(TAG, "Processed frame");
|
||||
}
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
#include <ctype.h>
|
||||
#include "stdio.h"
|
||||
|
||||
void processFrame (FrameStruct frame);
|
||||
void processFrame (const FrameStruct * frame);
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,110 @@
|
||||
#include "meshframing.h"
|
||||
#include "ch32v30x_gpio.h"
|
||||
#include "lib/config.h"
|
||||
#include "meshcore/stats.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "sx1262.h"
|
||||
#include "util/hexdump.h"
|
||||
#include "util/log.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "lib/cifra/sha2.h"
|
||||
|
||||
#define TAG "Meshframing"
|
||||
|
||||
int ReadFrame (FrameStruct *frame, int8_t *rssiPacket, int8_t *snrPacket, int8_t *rawSnr) {
|
||||
uint16_t irqRegs = GetIrqStatus();
|
||||
// uint8_t status = GetStatus();
|
||||
|
||||
if (irqRegs & SX126X_IRQ_RX_DONE) {
|
||||
// ClearIrqStatus(SX126X_IRQ_RX_DONE);
|
||||
ClearIrqStatus (SX126X_IRQ_ALL);
|
||||
|
||||
uint8_t offset = 0;
|
||||
uint8_t payloadLength = 0;
|
||||
GetRxBufferStatus (&payloadLength, &offset);
|
||||
|
||||
if (payloadLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GetPacketStatus (rssiPacket, snrPacket, rawSnr);
|
||||
|
||||
memset (frame, 0, sizeof (FrameStruct));
|
||||
WaitForIdle (BUSY_WAIT, "start ReadBuffer", 1);
|
||||
|
||||
uint8_t cmd[3] = {SX126X_CMD_READ_BUFFER, offset, SX126X_CMD_NOP};
|
||||
|
||||
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 0);
|
||||
|
||||
uint16_t curPayloadIndex = 0;
|
||||
uint8_t pathIndex = 0;
|
||||
uint8_t transportIndex = 0;
|
||||
uint8_t state = 0; // 0=header, 1=transport, 2=pathLen, 3=path, 4=payload
|
||||
|
||||
for (uint16_t i = 0; i < payloadLength + sizeof (cmd); i++) {
|
||||
uint8_t out = (i < sizeof (cmd)) ? cmd[i] : 0xFF;
|
||||
|
||||
// Wait TX ready
|
||||
while (!SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_TXE));
|
||||
SPI_I2S_SendData (SPI1, out);
|
||||
|
||||
// Wait RX ready
|
||||
while (!SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_RXNE));
|
||||
uint8_t in = (uint8_t)SPI_I2S_ReceiveData (SPI1);
|
||||
|
||||
// Only process payload bytes
|
||||
if (i >= sizeof (cmd)) {
|
||||
switch (state) {
|
||||
case 0: // header
|
||||
frame->header = in;
|
||||
state = ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD)
|
||||
? 1
|
||||
: 2;
|
||||
break;
|
||||
|
||||
case 1: // transportCodes[4]
|
||||
frame->transportCodes[transportIndex++] = in;
|
||||
if (transportIndex >= 4)
|
||||
state = 2;
|
||||
break;
|
||||
|
||||
case 2: // pathLen
|
||||
frame->path.pathLen = in;
|
||||
if (frame->path.pathLen > 64) {
|
||||
frame->path.pathLen = 64;
|
||||
}
|
||||
pathIndex = 0;
|
||||
state = (frame->path.pathLen > 0) ? 3 : 4;
|
||||
break;
|
||||
|
||||
case 3: // path
|
||||
frame->path.path[pathIndex++] = in;
|
||||
if (pathIndex >= frame->path.pathLen)
|
||||
state = 4;
|
||||
break;
|
||||
|
||||
case 4: // payload
|
||||
frame->payload[curPayloadIndex++] = in;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame->payloadLen = curPayloadIndex;
|
||||
|
||||
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 1);
|
||||
|
||||
WaitForIdle (BUSY_WAIT, "end ReadBuffer", 0);
|
||||
return payloadLength;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen) {
|
||||
hexdump ("RxDump", data, dataLen);
|
||||
FrameStruct frame;
|
||||
memset (&frame, 0, sizeof (frame));
|
||||
unsigned char index = 0;
|
||||
@@ -25,9 +123,9 @@ FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen) {
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void printFrameHeader (FrameStruct frame) {
|
||||
switch (frame.header & ROUTE_TYPE_MASK) {
|
||||
*/
|
||||
void printFrameHeader (const FrameStruct *frame) {
|
||||
switch (frame->header & ROUTE_TYPE_MASK) {
|
||||
case ROUTE_TYPE_TRANSPORT_FLOOD:
|
||||
printf ("transport flood");
|
||||
break;
|
||||
@@ -47,7 +145,7 @@ void printFrameHeader (FrameStruct frame) {
|
||||
|
||||
printf (", payload type is ");
|
||||
|
||||
switch (frame.header & PAYLOAD_TYPE_MASK) {
|
||||
switch (frame->header & PAYLOAD_TYPE_MASK) {
|
||||
case PAYLOAD_TYPE_REQ:
|
||||
printf ("request");
|
||||
break;
|
||||
@@ -101,67 +199,204 @@ void printFrameHeader (FrameStruct frame) {
|
||||
break;
|
||||
}
|
||||
char version[2];
|
||||
version[0] = (frame.header >> 6) + '0';
|
||||
version[0] = (frame->header >> 6) + '0';
|
||||
version[1] = 0;
|
||||
|
||||
printf (", payload version is %s ", version);
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
printf ("Transport codes: %d %d\n", *((uint16_t *)frame.transportCodes),
|
||||
*((uint16_t *)&(frame.transportCodes[2])));
|
||||
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
printf ("Transport codes: %d %d\n", *((uint16_t *)frame->transportCodes),
|
||||
*((uint16_t *)&(frame->transportCodes[2])));
|
||||
}
|
||||
printf ("Path is %d nodes long", frame.path.pathLen);
|
||||
printf ("Path is %d nodes long", frame->path.pathLen);
|
||||
|
||||
for (uint8_t pathIndex = 0; pathIndex < frame.path.pathLen; pathIndex++) {
|
||||
printf ("node %d - %02X, ", pathIndex, frame.path.path[pathIndex]);
|
||||
for (uint8_t pathIndex = 0; pathIndex < frame->path.pathLen; pathIndex++) {
|
||||
printf ("node %d - %02X, ", pathIndex, frame->path.path[pathIndex]);
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
void sendFrame (FrameStruct frame) {
|
||||
uint8_t txBuf[256];
|
||||
size_t offset = 0;
|
||||
void LoRaTransmit (const FrameStruct *frame) {
|
||||
uint8_t len = 2; // header + path_len
|
||||
|
||||
txBuf[offset++] = frame.header;
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (txBuf + offset, frame.transportCodes, 4);
|
||||
offset += 4;
|
||||
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
len += 4;
|
||||
}
|
||||
|
||||
if (frame.path.pathLen > 64) {
|
||||
frame.path.pathLen = 64;
|
||||
}
|
||||
len += frame->path.pathLen;
|
||||
len += frame->payloadLen;
|
||||
|
||||
txBuf[offset++] = frame.path.pathLen;
|
||||
uint16_t irqStatus;
|
||||
char rv = 0;
|
||||
|
||||
memcpy (txBuf + offset, frame.path.path, frame.path.pathLen);
|
||||
offset += frame.path.pathLen;
|
||||
if (txActive == 0) {
|
||||
txActive = 1;
|
||||
|
||||
uint16_t maxPayloadLen = 256 - offset;
|
||||
if (PacketParams[2] == 0x00) { // explicit header, variable length
|
||||
PacketParams[3] = len;
|
||||
}
|
||||
|
||||
uint16_t payloadLen = frame.payloadLen > maxPayloadLen ? maxPayloadLen : frame.payloadLen;
|
||||
WriteCommand (SX126X_CMD_SET_PACKET_PARAMS, PacketParams, 6);
|
||||
ClearIrqStatus (SX126X_IRQ_ALL);
|
||||
|
||||
memcpy (txBuf + offset, frame.payload, payloadLen);
|
||||
offset += payloadLen;
|
||||
WaitForIdle (BUSY_WAIT, "start WriteBuffer", 1);
|
||||
|
||||
hexdump ("TxDump", txBuf, offset);
|
||||
LoRaSend (txBuf, offset, SX126x_TXMODE_SYNC);
|
||||
}
|
||||
uint8_t cmdBuf[2] = {SX126X_CMD_WRITE_BUFFER, 0x00};
|
||||
uint8_t cmdLen = sizeof (cmdBuf);
|
||||
|
||||
void retransmitFrame (FrameStruct frame) {
|
||||
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) {
|
||||
frame.path.path[frame.path.pathLen++] = persistent.pubkey[0];
|
||||
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 0);
|
||||
|
||||
uint16_t payloadIndex = 0;
|
||||
uint8_t state = 0;
|
||||
uint8_t pathIndex = 0;
|
||||
uint8_t transportIndex = 0;
|
||||
|
||||
for (uint16_t i = 0; i < len + cmdLen; i++) {
|
||||
uint8_t out = 0xFF;
|
||||
|
||||
if (i < cmdLen) {
|
||||
out = cmdBuf[i];
|
||||
} else {
|
||||
switch (state) {
|
||||
case 0: // header
|
||||
out = frame->header;
|
||||
state = ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD)
|
||||
? 1
|
||||
: 2;
|
||||
break;
|
||||
|
||||
case 1: // transport codes
|
||||
out = frame->transportCodes[transportIndex++];
|
||||
if (transportIndex >= 4)
|
||||
state = 2;
|
||||
break;
|
||||
|
||||
case 2: // path length
|
||||
out = frame->path.pathLen;
|
||||
pathIndex = 0;
|
||||
state = (frame->path.pathLen > 0) ? 3 : 4;
|
||||
break;
|
||||
|
||||
case 3: // path
|
||||
out = frame->path.path[pathIndex++];
|
||||
if (pathIndex >= frame->path.pathLen)
|
||||
state = 4;
|
||||
break;
|
||||
|
||||
case 4: // payload
|
||||
out = frame->payload[payloadIndex++];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData (SPI1, out);
|
||||
|
||||
while (SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
(void)SPI_I2S_ReceiveData (SPI1); // discard
|
||||
}
|
||||
|
||||
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 1);
|
||||
|
||||
WaitForIdle (BUSY_WAIT, "end WriteBuffer", 0);
|
||||
|
||||
SetTx (5000);
|
||||
|
||||
irqStatus = GetIrqStatus();
|
||||
while (!(irqStatus & (SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT))) {
|
||||
vTaskDelay (1);
|
||||
irqStatus = GetIrqStatus();
|
||||
}
|
||||
|
||||
txActive = 0;
|
||||
SetRx (0xFFFFFF);
|
||||
|
||||
if (irqStatus & SX126X_IRQ_TX_DONE) {
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame.header & ROUTE_TYPE_DIRECT || frame.header & ROUTE_TYPE_TRANSPORT_DIRECT) {
|
||||
if (rv == 0) {
|
||||
txLost++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void sendFrame (const FrameStruct *frame) {
|
||||
uint8_t txBuf[256];
|
||||
size_t offset = 0;
|
||||
|
||||
txBuf[offset++] = frame->header;
|
||||
|
||||
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (txBuf + offset, frame->transportCodes, 4);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_FLOOD ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
stats.sentFloodCount++;
|
||||
}
|
||||
|
||||
if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_DIRECT ||
|
||||
(frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT) {
|
||||
stats.sentDirectCount++;
|
||||
}
|
||||
|
||||
stats.packetsSentCount++;
|
||||
|
||||
uint8_t pathLen = frame->path.pathLen;
|
||||
|
||||
|
||||
if (pathLen > 64) {
|
||||
pathLen = 64;
|
||||
}
|
||||
|
||||
txBuf[offset++] = pathLen;
|
||||
|
||||
memcpy (txBuf + offset, frame->path.path, pathLen);
|
||||
hexdump ("TxDump Path", frame->path.path, frame->path.pathLen);
|
||||
offset += pathLen;
|
||||
|
||||
uint16_t maxPayloadLen = 256 - offset;
|
||||
|
||||
uint16_t payloadLen = frame->payloadLen > maxPayloadLen ? maxPayloadLen : frame->payloadLen;
|
||||
|
||||
memcpy (txBuf + offset, frame->payload, payloadLen);
|
||||
offset += payloadLen;
|
||||
|
||||
|
||||
hexdump ("TxDump", txBuf, offset);
|
||||
hexdump ("TxDumpPayload", frame->payload, frame->payloadLen);
|
||||
TickType_t start, end;
|
||||
start = xTaskGetTickCount();
|
||||
LoRaSend (txBuf, offset, SX126x_TXMODE_SYNC);
|
||||
end = xTaskGetTickCount();
|
||||
tickAirtime += end - start;
|
||||
}
|
||||
*/
|
||||
|
||||
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");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->header & ROUTE_TYPE_DIRECT || frame->header & ROUTE_TYPE_TRANSPORT_DIRECT) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
|
||||
@@ -173,8 +408,8 @@ int encrypt_then_mac (const uint8_t *aes_key, const uint8_t keySize, const uint8
|
||||
|
||||
// prepare padded buffer
|
||||
uint8_t padded[padded_len];
|
||||
memset(padded, 0, padded_len); // zero padding
|
||||
memcpy(padded, plaintext, plen); // copy plaintext
|
||||
memset (padded, 0, padded_len); // zero padding
|
||||
memcpy (padded, plaintext, plen); // copy plaintext
|
||||
|
||||
// ciphertext will go right after HMAC
|
||||
uint8_t *ciphertext = output + HMAC_SIZE;
|
||||
@@ -202,7 +437,8 @@ int mac_then_decrypt (const uint8_t *aes_key, const uint8_t keySize, const uint8
|
||||
const uint8_t *ciphertext = input + HMAC_SIZE;
|
||||
size_t clen = ilen - HMAC_SIZE;
|
||||
|
||||
if (clen % 16 != 0) return -2; // must be multiple of block size
|
||||
if (clen % 16 != 0)
|
||||
return -2; // must be multiple of block size
|
||||
|
||||
uint8_t calc_mac[32]; // full SHA-256
|
||||
hmac_sha256 (aes_key, keySize, ciphertext, clen, calc_mac);
|
||||
@@ -211,4 +447,26 @@ int mac_then_decrypt (const uint8_t *aes_key, const uint8_t keySize, const uint8
|
||||
return -2;
|
||||
|
||||
return aes_decrypt_ecb (aes_key, 16, ciphertext, clen, plaintext);
|
||||
}
|
||||
|
||||
uint16_t getTransportCode (const FrameStruct *frame) {
|
||||
uint16_t code;
|
||||
/*
|
||||
// compute HMAC over ciphertext
|
||||
uint8_t mac[32]; // full SHA-256
|
||||
cf_hmac_ctx ctx;
|
||||
cf_hmac_init (&ctx, &cf_sha256, key, sizeof(key));
|
||||
cf_hmac_update (&ctx, &(frame->header), sizeof (frame->header));
|
||||
cf_hmac_update (&ctx, frame->payload, frame->payloadLen);
|
||||
cf_hmac_finish (&ctx, mac);
|
||||
|
||||
// copy only HMAC_SIZE bytes of MAC
|
||||
memcpy (&code, mac, HMAC_SIZE);
|
||||
*/
|
||||
if (code == 0) { // reserve codes 0000 and FFFF
|
||||
code++;
|
||||
} else if (code == 0xFFFF) {
|
||||
code--;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
@@ -12,13 +12,20 @@
|
||||
#define HMAC_SIZE 2 // meshcore size
|
||||
#define MAX_FLOOD_TTL 64
|
||||
|
||||
int ReadFrame(FrameStruct *frame, int8_t *rssiPacket, int8_t *snrPacket, int8_t *rawSnr);
|
||||
|
||||
void LoRaTransmit (const FrameStruct *frame);
|
||||
|
||||
/*
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen);
|
||||
|
||||
void printFrameHeader (FrameStruct frame) ;
|
||||
void sendFrame (const FrameStruct * frame);
|
||||
*/
|
||||
|
||||
void sendFrame (FrameStruct frame);
|
||||
void printFrameHeader (const FrameStruct * frame) ;
|
||||
|
||||
void retransmitFrame (FrameStruct frame) ;
|
||||
//CALL LAST, PATH GETS MODIFIED
|
||||
void retransmitFrame (FrameStruct * frame) ;
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
|
||||
@@ -26,4 +33,5 @@ int encrypt_then_mac (const uint8_t *aes_key, const uint8_t keySize, const uint8
|
||||
|
||||
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t keySize, const uint8_t *input, size_t ilen, uint8_t *plaintext);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
void sendDiscreteAck (uint8_t *data, const uint8_t len, uint8_t *senderPubKey) {
|
||||
FrameStruct frame;
|
||||
frame.path.pathLen = 0;
|
||||
memset (&frame, 0, sizeof (frame));
|
||||
|
||||
// 1. Header
|
||||
@@ -38,5 +39,5 @@ void sendDiscreteAck (uint8_t *data, const uint8_t len, uint8_t *senderPubKey) {
|
||||
frame.payloadLen = 4;
|
||||
|
||||
|
||||
sendFrame (frame);
|
||||
LoRaTransmit (&frame);
|
||||
}
|
||||
@@ -7,186 +7,202 @@
|
||||
#include "advert.h"
|
||||
#include "util/hexdump.h"
|
||||
#include "lib/base64.h"
|
||||
#include "util/log.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#define TAG "Advert"
|
||||
|
||||
void sendAdvert() {
|
||||
AdvertisementPayload ad;
|
||||
memcpy (ad.pubKey, persistent.pubkey, sizeof (ad.pubKey));
|
||||
ad.dataFlags = ADVERTISEMENT_FLAG_HAS_NAME;
|
||||
if (persistent.nodeType == NODE_TYPE_CHAT_NODE) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_CHAT_NODE;
|
||||
} else if (persistent.nodeType == NODE_TYPE_REPEATER) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_REAPEATER;
|
||||
} else if (persistent.nodeType == NODE_TYPE_ROOM_SERVER) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_ROOM_SERVER;
|
||||
} else if (persistent.nodeType == NODE_TYPE_SENSOR) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_SENSOR;
|
||||
}
|
||||
strcpy (ad.nodeName, persistent.nodeName);
|
||||
ad.timestamp = RTC_GetCounter();
|
||||
|
||||
uint8_t app_data[40];
|
||||
size_t app_len = 0;
|
||||
|
||||
app_data[app_len++] = ad.dataFlags;
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (app_data + app_len, &ad.latitude, sizeof (ad.latitude));
|
||||
app_len += sizeof (ad.latitude);
|
||||
memcpy (app_data + app_len, &ad.longitude, sizeof (ad.longitude));
|
||||
app_len += sizeof (ad.longitude);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (app_data + app_len, &ad.rfu1, sizeof (ad.rfu1));
|
||||
app_len += sizeof (ad.rfu1);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (app_data + app_len, &ad.rfu2, sizeof (ad.rfu2));
|
||||
app_len += sizeof (ad.rfu2);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME) {
|
||||
size_t nodenameLen = strlen (ad.nodeName);
|
||||
memcpy (app_data + app_len, ad.nodeName, nodenameLen);
|
||||
app_len += nodenameLen;
|
||||
}
|
||||
|
||||
// 2. Reserve frame and build payload header
|
||||
void sendAdvert (uint8_t shouldFlood) {
|
||||
printf ("High-water mark before preparing advert: %u\n", uxTaskGetStackHighWaterMark (NULL));
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_ADVERT | PAYLOAD_VERSION_0;
|
||||
|
||||
size_t offset = 0;
|
||||
memcpy (frame.payload + offset, ad.pubKey, sizeof (ad.pubKey));
|
||||
offset += sizeof (ad.pubKey);
|
||||
|
||||
memcpy (frame.payload + offset, &ad.timestamp, sizeof (ad.timestamp));
|
||||
offset += sizeof (ad.timestamp);
|
||||
frame.header = (shouldFlood ? ROUTE_TYPE_FLOOD : ROUTE_TYPE_DIRECT) | PAYLOAD_TYPE_ADVERT | PAYLOAD_VERSION_0;
|
||||
|
||||
// reserve signature space
|
||||
/* ---- public key ---- */
|
||||
memcpy (frame.payload + offset, persistent.pubkey, 32);
|
||||
offset += 32;
|
||||
|
||||
/* ---- timestamp ---- */
|
||||
uint32_t timestamp = RTC_GetCounter();
|
||||
memcpy (frame.payload + offset, ×tamp, sizeof (timestamp));
|
||||
offset += sizeof (timestamp);
|
||||
|
||||
/* ---- reserve signature ---- */
|
||||
uint8_t *signature_pos = frame.payload + offset;
|
||||
offset += 64;
|
||||
|
||||
// append app_data after signature
|
||||
memcpy (frame.payload + offset, app_data, app_len);
|
||||
offset += app_len;
|
||||
/* ---- build app data directly into payload ---- */
|
||||
size_t app_start = offset;
|
||||
|
||||
// 3. Sign pubKey + timestamp + app_data
|
||||
uint8_t message[76];
|
||||
size_t msg_len = 0;
|
||||
memcpy (message + msg_len, ad.pubKey, sizeof (ad.pubKey));
|
||||
msg_len += sizeof (ad.pubKey);
|
||||
memcpy (message + msg_len, &ad.timestamp, sizeof (ad.timestamp));
|
||||
msg_len += sizeof (ad.timestamp);
|
||||
memcpy (message + msg_len, app_data, app_len);
|
||||
msg_len += app_len;
|
||||
uint8_t dataFlags = ADVERTISEMENT_FLAG_HAS_NAME;
|
||||
if (persistent.nodeType == NODE_TYPE_CHAT_NODE)
|
||||
dataFlags |= ADVERTISEMENT_FLAG_IS_CHAT_NODE;
|
||||
else if (persistent.nodeType == NODE_TYPE_REPEATER)
|
||||
dataFlags |= ADVERTISEMENT_FLAG_IS_REAPEATER;
|
||||
else if (persistent.nodeType == NODE_TYPE_ROOM_SERVER)
|
||||
dataFlags |= ADVERTISEMENT_FLAG_IS_ROOM_SERVER;
|
||||
else if (persistent.nodeType == NODE_TYPE_SENSOR)
|
||||
dataFlags |= ADVERTISEMENT_FLAG_IS_SENSOR;
|
||||
|
||||
ed25519_sign (signature_pos, message, msg_len, persistent.pubkey, persistent.privkey);
|
||||
frame.payload[offset++] = dataFlags;
|
||||
|
||||
hexdump ("Complete advert", frame.payload, offset);
|
||||
if (dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (frame.payload + offset, &persistent.latitude, sizeof (persistent.latitude));
|
||||
offset += sizeof (persistent.latitude);
|
||||
|
||||
hexdump ("Public key", ad.pubKey, 32);
|
||||
memcpy (frame.payload + offset, &persistent.longitude, sizeof (persistent.longitude));
|
||||
offset += sizeof (persistent.longitude);
|
||||
}
|
||||
/*
|
||||
|
||||
if (dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy(frame.payload + offset, &persistent.rfu1, sizeof(persistent.rfu1));
|
||||
offset += sizeof(persistent.rfu1);
|
||||
}
|
||||
|
||||
if (dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy(frame.payload + offset, &persistent.rfu2, sizeof(persistent.rfu2));
|
||||
offset += sizeof(persistent.rfu2);
|
||||
}
|
||||
*/
|
||||
|
||||
if (dataFlags & ADVERTISEMENT_FLAG_HAS_NAME) {
|
||||
size_t nameLen = strlen (persistent.nodeName);
|
||||
memcpy (frame.payload + offset, persistent.nodeName, nameLen);
|
||||
offset += nameLen;
|
||||
}
|
||||
|
||||
size_t app_len = offset - app_start;
|
||||
|
||||
frame.payloadLen = offset;
|
||||
/* ---- sign directly over payload ---- */
|
||||
printf ("High-water mark before signing: %u\n", uxTaskGetStackHighWaterMark (NULL));
|
||||
ed25519_sign_ad (&frame);
|
||||
printf ("High-water mark after signing: %u\n", uxTaskGetStackHighWaterMark (NULL));
|
||||
|
||||
/* ---- debug ---- */
|
||||
hexdump ("Public key", frame.payload, 32);
|
||||
hexdump ("Signature", signature_pos, 64);
|
||||
hexdump ("Appdata", frame.payload + app_start, app_len);
|
||||
printf ("Timestamp is %lu\n", timestamp);
|
||||
printf ("NodeName %s\n", persistent.nodeName);
|
||||
|
||||
printf ("Timestamp is %d\n", ad.timestamp);
|
||||
|
||||
printf ("NodeName %s\n", ad.nodeName);
|
||||
|
||||
hexdump ("Appdata", app_data, app_len);
|
||||
|
||||
// 5. Set payload length and send
|
||||
/* ---- send ---- */
|
||||
frame.payloadLen = offset;
|
||||
frame.path.pathLen = 0;
|
||||
sendFrame (frame);
|
||||
LoRaTransmit (&frame);
|
||||
}
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame) {
|
||||
void decodeAdvertisement (const FrameStruct *frame) {
|
||||
AdvertisementPayload advert;
|
||||
memset (&advert, 0, sizeof (advert));
|
||||
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_ADVERT) {
|
||||
return advert;
|
||||
advert.valid = 0;
|
||||
if (frame->payloadLen < 101) {
|
||||
MESH_LOGW (TAG, "Advertisement frame too short (%d < 101)", frame->payloadLen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ed25519_verify_ad (frame) != 1) {
|
||||
MESH_LOGW (TAG, "Incorrect signature");
|
||||
return;
|
||||
}
|
||||
advert.valid = 1;
|
||||
|
||||
unsigned char index = 0;
|
||||
|
||||
memcpy (advert.pubKey, frame.payload + index, 32);
|
||||
memcpy (advert.pubKey, frame->payload + index, 32);
|
||||
index += 32;
|
||||
|
||||
memcpy (&advert.timestamp, frame.payload + index, 4);
|
||||
memcpy (&advert.timestamp, frame->payload + index, 4);
|
||||
index += 4;
|
||||
|
||||
memcpy (advert.signature, frame.payload + index, 64);
|
||||
memcpy (advert.signature, frame->payload + index, 64);
|
||||
index += 64;
|
||||
|
||||
advert.dataFlags = frame.payload[index++];
|
||||
advert.dataFlags = frame->payload[index++];
|
||||
|
||||
uint8_t expectedLen = 101;
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (&advert.latitude, frame.payload + index, 4);
|
||||
expectedLen += 8;
|
||||
}
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
expectedLen += 2;
|
||||
}
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
expectedLen += 2;
|
||||
}
|
||||
|
||||
if (frame->payloadLen < expectedLen) {
|
||||
MESH_LOGW (TAG, "Advertisement frame with data too short (%d < %d)", frame->payloadLen, expectedLen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (&advert.latitude, frame->payload + index, 4);
|
||||
index += 4;
|
||||
memcpy (&advert.longitude, frame.payload + index, 4);
|
||||
memcpy (&advert.longitude, frame->payload + index, 4);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (&advert.rfu1, frame.payload + index, 2);
|
||||
memcpy (&advert.rfu1, frame->payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (&advert.rfu2, frame.payload + index, 2);
|
||||
memcpy (&advert.rfu2, frame->payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
unsigned char nameLen = frame.payloadLen - index;
|
||||
if (nameLen > 32) {
|
||||
nameLen = 32;
|
||||
unsigned char nameLen = frame->payloadLen - index;
|
||||
|
||||
if (nameLen > 31) {
|
||||
nameLen = 31; // leave space for null
|
||||
}
|
||||
memcpy (advert.nodeName, frame.payload + index, nameLen);
|
||||
advert.nodeName[frame.payloadLen - index] = 0;
|
||||
memcpy (advert.nodeName, frame->payload + index, nameLen);
|
||||
advert.nodeName[nameLen] = 0;
|
||||
|
||||
|
||||
NodeEntry *node = getNode (advert.pubKey[0]);
|
||||
printAdvertisement (&advert);
|
||||
saveAdvert (&advert);
|
||||
}
|
||||
|
||||
void saveAdvert (const AdvertisementPayload *advert) {
|
||||
NodeEntry *node = getNode (advert->pubKey[0]);
|
||||
if (node == NULL) {
|
||||
node = getNextNode();
|
||||
memset (node, 0, sizeof (NodeEntry));
|
||||
}
|
||||
|
||||
memcpy (node->name, advert.nodeName, sizeof (node->name));
|
||||
memcpy (node->pubKey, advert.pubKey, sizeof (node->pubKey));
|
||||
ed25519_key_exchange ((unsigned char *)node->secret, advert.pubKey, persistent.privkey);
|
||||
node->gps_latitude = advert.latitude;
|
||||
node->gps_longitude = advert.longitude;
|
||||
memcpy (node->name, advert->nodeName, sizeof (node->name));
|
||||
memcpy (node->pubKey, advert->pubKey, sizeof (node->pubKey));
|
||||
ed25519_key_exchange ((unsigned char *)node->secret, advert->pubKey, persistent.privkey);
|
||||
node->gps_latitude = advert->latitude;
|
||||
node->gps_longitude = advert->longitude;
|
||||
// ADD PATH
|
||||
node->type = advert.dataFlags & 0x0F;
|
||||
node->type = advert->dataFlags & 0x0F;
|
||||
node->last_seen_lt = RTC_GetCounter();
|
||||
node->last_seen_rt = advert.timestamp;
|
||||
|
||||
|
||||
return advert;
|
||||
node->last_seen_rt = advert->timestamp;
|
||||
}
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert) {
|
||||
unsigned char keyBuf[50];
|
||||
unsigned char sigBuf[90];
|
||||
memset (keyBuf, 0, sizeof (keyBuf));
|
||||
memset (sigBuf, 0, sizeof (sigBuf));
|
||||
base64_encode (advert.pubKey, 32, keyBuf);
|
||||
base64_encode (advert.signature, 64, sigBuf);
|
||||
void printAdvertisement (const AdvertisementPayload *advert) {
|
||||
printf (
|
||||
"%s on %ld with type %s on %s location %ld %ld\n",
|
||||
advert->dataFlags & ADVERTISEMENT_FLAG_HAS_NAME
|
||||
? advert->nodeName
|
||||
: "nameless node",
|
||||
advert->timestamp,
|
||||
(advert->dataFlags & 0x07) == 0x04 ? "sensor"
|
||||
: (advert->dataFlags & 0x07) == 0x03 ? "room server"
|
||||
: (advert->dataFlags & 0x07) == 0x02 ? "repeater"
|
||||
: "chat node",
|
||||
advert->dataFlags & 0x80 ? "known" : "unknown",
|
||||
advert->latitude,
|
||||
advert->longitude);
|
||||
|
||||
printf ("%s on %ld with type %s on %s location %ld %ld, public key %s and "
|
||||
"signature %s\n",
|
||||
advert.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME ? advert.nodeName
|
||||
: "nameless node",
|
||||
advert.timestamp,
|
||||
(advert.dataFlags & 0x07) == 0x04
|
||||
? "sensor"
|
||||
: ((advert.dataFlags & 0x07) == 0x03
|
||||
? "room server"
|
||||
: ((advert.dataFlags & 0x07) == 0x02 ? "repeater"
|
||||
: "chat node")),
|
||||
advert.dataFlags & 0x80 ? "known" : "unknown", advert.latitude,
|
||||
advert.longitude, keyBuf, sigBuf);
|
||||
}
|
||||
hexdump ("Public key", advert->pubKey, 32);
|
||||
hexdump ("Signature", advert->signature, 64);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
void sendAdvert();
|
||||
void sendAdvert (uint8_t shouldFlood);
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame);
|
||||
void decodeAdvertisement (const FrameStruct * frame);
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert);
|
||||
void printAdvertisement (const AdvertisementPayload * advert);
|
||||
|
||||
void saveAdvert(const AdvertisementPayload * advert);
|
||||
|
||||
#endif
|
||||
@@ -10,9 +10,10 @@
|
||||
|
||||
#define TAG "Anonymous"
|
||||
|
||||
void sendAnonymousRequest (NodeEntry *targetNode, const uint8_t *password, uint32_t sync) {
|
||||
void sendAnonymousRequest (const NodeEntry *targetNode, const uint8_t *password, uint32_t sync) {
|
||||
uint8_t passwordLen = strlen ((const char *)password);
|
||||
FrameStruct frame;
|
||||
frame.path.pathLen = 0;
|
||||
uint8_t offset = 0;
|
||||
|
||||
// 1. Frame header
|
||||
@@ -61,36 +62,103 @@ void sendAnonymousRequest (NodeEntry *targetNode, const uint8_t *password, uint3
|
||||
|
||||
// 5. Finalize and send
|
||||
frame.payloadLen = offset;
|
||||
memcpy(&(frame.path), &(targetNode->path), sizeof(frame.path));
|
||||
memcpy (&(frame.path), &(targetNode->path), sizeof (frame.path));
|
||||
|
||||
hexdump ("Anon payload", frame.payload, frame.payloadLen);
|
||||
|
||||
sendFrame (frame);
|
||||
LoRaTransmit (&frame);
|
||||
}
|
||||
|
||||
AnonymousRequestPayload decodeAnonReq (FrameStruct frame) {
|
||||
void printAnonRequest (const AnonymousRequestPayload *req, int isRoomServer) {
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
printf ("AnonymousRequestPayload at %p\n", (void *)req);
|
||||
printf (" destination hash: 0x%02X\n", req->destinationHash);
|
||||
|
||||
printf (" sender pubKey: ");
|
||||
for (int i = 0; i < sizeof (req->pubKey); i++) {
|
||||
printf ("%02X", req->pubKey[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
printf (" cipher MAC: 0x%04X\n", req->cipherMAC);
|
||||
|
||||
printf (" decrypted payload (%u bytes):\n", req->payloadLen);
|
||||
uint8_t index = 0;
|
||||
|
||||
// timestamp (first 4 bytes)
|
||||
if (req->payloadLen >= 4) {
|
||||
uint32_t timestamp = req->payload[index++];
|
||||
timestamp |= req->payload[index++] << 8;
|
||||
timestamp |= req->payload[index++] << 16;
|
||||
timestamp |= req->payload[index++] << 24;
|
||||
printf (" timestamp: %u\n", timestamp);
|
||||
}
|
||||
|
||||
// room server sync timestamp
|
||||
if (isRoomServer && req->payloadLen >= index + 4) {
|
||||
uint32_t syncTimestamp = req->payload[index++];
|
||||
syncTimestamp |= req->payload[index++] << 8;
|
||||
syncTimestamp |= req->payload[index++] << 16;
|
||||
syncTimestamp |= req->payload[index++] << 24;
|
||||
printf (" sync timestamp: %u\n", syncTimestamp);
|
||||
}
|
||||
|
||||
|
||||
// remaining bytes = password
|
||||
if (index < req->payloadLen) {
|
||||
uint8_t passwordLen = req->payloadLen - index;
|
||||
if (passwordLen > 16)
|
||||
passwordLen = 16;
|
||||
passwordLen = strnlen (&(req->payload[index]), passwordLen);
|
||||
printf (" password: ");
|
||||
for (uint8_t i = 0; i < passwordLen; i++) {
|
||||
printf ("%c", req->payload[i + index]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
size_t strnlen (const char *s, size_t maxLen) {
|
||||
size_t len = 0;
|
||||
while (len < maxLen && s[len] != '\0') {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void decodeAnonReq (const FrameStruct *frame) {
|
||||
uint8_t index = 0;
|
||||
AnonymousRequestPayload anonReq;
|
||||
anonReq.destinationHash = frame.payload[index++];
|
||||
memcpy (anonReq.pubKey, &(frame.payload[index]), sizeof (anonReq.pubKey));
|
||||
|
||||
anonReq.destinationHash = frame->payload[index++];
|
||||
memcpy (anonReq.pubKey, &(frame->payload[index]), sizeof (anonReq.pubKey));
|
||||
index += sizeof (anonReq.pubKey);
|
||||
anonReq.cipherMAC = frame.payload[index];
|
||||
anonReq.cipherMAC |= frame.payload[index + 1] << 8;
|
||||
anonReq.cipherMAC = frame->payload[index];
|
||||
anonReq.cipherMAC |= frame->payload[index + 1] << 8;
|
||||
|
||||
NodeEntry *foundNode = getNode (anonReq.pubKey[0]);
|
||||
if (foundNode == NULL) {
|
||||
foundNode = getNextNode();
|
||||
|
||||
strcpy (foundNode->name, "Anonymous node");
|
||||
memcpy (foundNode->pubKey, anonReq.pubKey, sizeof (foundNode->pubKey));
|
||||
ed25519_key_exchange ((unsigned char *)foundNode->secret, anonReq.pubKey, persistent.privkey);
|
||||
foundNode->gps_latitude = 0;
|
||||
foundNode->gps_longitude = 0;
|
||||
// ADD PATH
|
||||
foundNode->type = 0;
|
||||
foundNode->last_seen_lt = RTC_GetCounter();
|
||||
|
||||
MESH_LOGI (TAG, "New anonymous node created: %s", foundNode->name);
|
||||
} else {
|
||||
MESH_LOGD (TAG, "Existing node found for pubKey[0]=0x%02X", anonReq.pubKey[0]);
|
||||
}
|
||||
mac_then_decrypt (foundNode->secret, 32, &(frame.payload[index]), frame.payloadLen - index, anonReq.payload);
|
||||
anonReq.payloadLen = frame.payloadLen - index - 2;
|
||||
|
||||
mac_then_decrypt (foundNode->secret, 32, &(frame->payload[index]), frame->payloadLen - index, anonReq.payload);
|
||||
anonReq.payloadLen = frame->payloadLen - index - 2;
|
||||
|
||||
hexdump ("AnonReq payload", anonReq.payload, anonReq.payloadLen);
|
||||
|
||||
uint8_t index2 = 0;
|
||||
foundNode->last_seen_rt = anonReq.payload[index2++];
|
||||
foundNode->last_seen_rt |= anonReq.payload[index2++] << 8;
|
||||
@@ -104,30 +172,39 @@ AnonymousRequestPayload decodeAnonReq (FrameStruct frame) {
|
||||
foundNode->sync_timestamp |= anonReq.payload[index2++] << 24;
|
||||
}
|
||||
|
||||
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);
|
||||
uint8_t passwordBuf[16];
|
||||
memcpy (passwordBuf, &(anonReq.payload[index2]), passwordLen);
|
||||
if (memcmp (passwordBuf, persistent.password, sizeof (persistent.password)) == 0) {
|
||||
|
||||
if (memcmp (passwordBuf, persistent.password, passwordLen) == 0) {
|
||||
foundNode->authenticated = 1;
|
||||
Response resp;
|
||||
resp.tag = RTC_GetCounter();
|
||||
uint8_t index3 = 0;
|
||||
uint32_t randOut = rand();
|
||||
resp.data[index3++] = RESP_SERVER_LOGIN_OK;
|
||||
resp.data[index3++] = 0;//legacy
|
||||
resp.data[index3++] = 1;//isadmin
|
||||
resp.data[index3++] = PERM_ACL_ADMIN;//permissions
|
||||
resp.data[index3++] = randOut & 0xFF;//rng
|
||||
resp.data[index3++] = (randOut >> 8) & 0xFF;
|
||||
resp.data[index3++] = (randOut >> 16) & 0xFF;
|
||||
resp.data[index3++] = (randOut >> 24) & 0xFF;
|
||||
resp.data[index3++] = FIRMWARE_VER_LEVEL;
|
||||
resp.dataLen = index3;
|
||||
sendEncryptedResponse(foundNode, &resp);
|
||||
MESH_LOGI (TAG, "Password correct, node %s authenticated.", foundNode->name);
|
||||
|
||||
MESH_LOGI (TAG, "Login response sent to node %s.", foundNode->name);
|
||||
} else {
|
||||
MESH_LOGW (TAG, "Password incorrect for node %s.", foundNode->name);
|
||||
}
|
||||
|
||||
return anonReq;
|
||||
}
|
||||
Response resp;
|
||||
resp.tag = RTC_GetCounter();
|
||||
uint8_t index3 = 0;
|
||||
uint32_t randOut = rand();
|
||||
resp.data[index3++] = RESP_SERVER_LOGIN_OK;
|
||||
resp.data[index3++] = 0; // legacy
|
||||
resp.data[index3++] = foundNode->authenticated; // isadmin
|
||||
resp.data[index3++] = foundNode->authenticated ? PERM_ACL_ADMIN : PERM_ACL_GUEST; // permissions
|
||||
resp.data[index3++] = randOut & 0xFF;
|
||||
resp.data[index3++] = (randOut >> 8) & 0xFF;
|
||||
resp.data[index3++] = (randOut >> 16) & 0xFF;
|
||||
resp.data[index3++] = (randOut >> 24) & 0xFF;
|
||||
resp.data[index3++] = FIRMWARE_VER_LEVEL;
|
||||
resp.dataLen = index3;
|
||||
sendEncryptedResponse (foundNode, &resp);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "lib/config.h"
|
||||
|
||||
AnonymousRequestPayload decodeAnonReq (FrameStruct frame);
|
||||
void decodeAnonReq (const FrameStruct * frame);
|
||||
|
||||
void sendAnonymousRequest (NodeEntry *targetNode, const uint8_t *password, uint32_t sync);
|
||||
void sendAnonymousRequest (const NodeEntry *targetNode, const uint8_t *password, uint32_t sync);
|
||||
|
||||
#endif
|
||||
@@ -1,13 +1,19 @@
|
||||
#include "lib/config.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "control.h"
|
||||
#include "meshcore/stats.h"
|
||||
#include "string.h"
|
||||
#include "util/hexdump.h"
|
||||
#include "util/log.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define TAG "Control"
|
||||
|
||||
void sendDiscoverRequest(const DiscoverRequestPayload *discReq) {
|
||||
void sendDiscoverRequest (const DiscoverRequestPayload *discReq) {
|
||||
|
||||
FrameStruct frame;
|
||||
frame.path.pathLen = 0;
|
||||
uint8_t offset = 0;
|
||||
|
||||
// Build payload
|
||||
@@ -21,7 +27,7 @@ void sendDiscoverRequest(const DiscoverRequestPayload *discReq) {
|
||||
frame.payload[offset++] = (discReq->tag >> 24) & 0xFF;
|
||||
|
||||
// optional `since`
|
||||
if (discReq->since != 0) { // or another condition if you want to always include
|
||||
if (discReq->since != 0) { // or another condition if you want to always include
|
||||
frame.payload[offset++] = (discReq->since >> 0) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->since >> 8) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->since >> 16) & 0xFF;
|
||||
@@ -30,47 +36,110 @@ void sendDiscoverRequest(const DiscoverRequestPayload *discReq) {
|
||||
|
||||
frame.payloadLen = offset;
|
||||
|
||||
sendFrame(frame);
|
||||
LoRaTransmit (&frame);
|
||||
}
|
||||
|
||||
void sendDiscoverResponse (const DiscoverResponsePayload *discResp) {
|
||||
FrameStruct frame;
|
||||
frame.path.pathLen = 0;
|
||||
uint8_t offset = 0;
|
||||
|
||||
void decodeControlFrame(FrameStruct frame) {
|
||||
/* Control type + node type (lower nibble) */
|
||||
frame.payload[offset++] =
|
||||
(discResp->nodeType & 0x0F) |
|
||||
CONTROL_DATA_FLAG_DISCOVER_RESP;
|
||||
|
||||
/* SNR */
|
||||
frame.payload[offset++] = (uint8_t)discResp->snr;
|
||||
|
||||
/* Tag (LE) */
|
||||
frame.payload[offset++] = (discResp->tag >> 0) & 0xFF;
|
||||
frame.payload[offset++] = (discResp->tag >> 8) & 0xFF;
|
||||
frame.payload[offset++] = (discResp->tag >> 16) & 0xFF;
|
||||
frame.payload[offset++] = (discResp->tag >> 24) & 0xFF;
|
||||
|
||||
/* Pubkey */
|
||||
if (discResp->pubkeyLen > 0) {
|
||||
memcpy (&frame.payload[offset],
|
||||
discResp->pubkey,
|
||||
discResp->pubkeyLen);
|
||||
offset += discResp->pubkeyLen;
|
||||
}
|
||||
|
||||
frame.payloadLen = offset;
|
||||
|
||||
LoRaTransmit (&frame);
|
||||
}
|
||||
|
||||
void printDiscoverRequest (const DiscoverRequestPayload *p) {
|
||||
printf ("=== Discover Request ===\n");
|
||||
printf ("prefixOnly : %u\n", p->prefixOnly);
|
||||
printf ("typeFilter : 0x%02X\n", p->typeFilter);
|
||||
printf ("tag : 0x%08lX\n", (unsigned long)p->tag);
|
||||
printf ("since : 0x%08lX\n", (unsigned long)p->since);
|
||||
}
|
||||
|
||||
void printDiscoverResponse (const DiscoverResponsePayload *p) {
|
||||
printf ("=== Discover Response ===\n");
|
||||
printf ("nodeType : %u\n", p->nodeType);
|
||||
printf ("snr : %u\n", p->snr);
|
||||
printf ("tag : 0x%08lX\n", (unsigned long)p->tag);
|
||||
|
||||
hexdump ("pubkey : ", p->pubkey, p->pubkeyLen);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
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) {
|
||||
DiscoverRequestPayload discReq;
|
||||
discReq.prefixOnly = frame.payload[index++] & 0x01;
|
||||
uint8_t type = frame->payload[index] & 0xF0;
|
||||
if (type == CONTROL_DATA_FLAG_TYPE_NODE_DISCOVER_REQ) {
|
||||
DiscoverRequestPayload discReq;
|
||||
discReq.prefixOnly = frame->payload[index++] & 0x01;
|
||||
|
||||
discReq.typeFilter = frame.payload[index++];
|
||||
discReq.typeFilter = frame->payload[index++];
|
||||
|
||||
discReq.tag = frame.payload[index++];
|
||||
discReq.tag |= frame.payload[index++] << 8;
|
||||
discReq.tag |= frame.payload[index++] << 16;
|
||||
discReq.tag |= frame.payload[index++] << 24;
|
||||
|
||||
if (index < frame.payloadLen) {
|
||||
discReq.since = frame.payload[index++];
|
||||
discReq.since |= frame.payload[index++] << 8;
|
||||
discReq.since |= frame.payload[index++] << 16;
|
||||
discReq.since |= frame.payload[index++] << 24;
|
||||
}
|
||||
|
||||
} else if (type == CONTROL_DATA_FLAG_DISCOVER_RESP) {
|
||||
DiscoverResponsePayload discResp;
|
||||
discResp.nodeType = frame.payload[index++] & 0x0F;
|
||||
|
||||
discResp.snr = frame.payload[index++];
|
||||
|
||||
discResp.tag = frame.payload[index++];
|
||||
discResp.tag |= frame.payload[index++] << 8;
|
||||
discResp.tag |= frame.payload[index++] << 16;
|
||||
discResp.tag |= frame.payload[index++] << 24;
|
||||
|
||||
uint8_t remainingLen = frame.payloadLen - index;
|
||||
|
||||
uint8_t pubKeyLen = (remainingLen > 8) ? sizeof(discResp.pubkey) : 8;
|
||||
memcpy(discResp.pubkey, &(frame.payload[index]), pubKeyLen);
|
||||
index += pubKeyLen;
|
||||
discReq.tag = frame->payload[index++];
|
||||
discReq.tag |= frame->payload[index++] << 8;
|
||||
discReq.tag |= frame->payload[index++] << 16;
|
||||
discReq.tag |= frame->payload[index++] << 24;
|
||||
|
||||
if (index < frame->payloadLen) {
|
||||
discReq.since = frame->payload[index++];
|
||||
discReq.since |= frame->payload[index++] << 8;
|
||||
discReq.since |= frame->payload[index++] << 16;
|
||||
discReq.since |= frame->payload[index++] << 24;
|
||||
}
|
||||
printDiscoverRequest (&discReq);
|
||||
if ((discReq.typeFilter >> 2) & persistent.nodeType) {
|
||||
DiscoverResponsePayload discResp;
|
||||
|
||||
discResp.tag = discReq.tag;
|
||||
discResp.nodeType = persistent.nodeType;
|
||||
discResp.pubkeyLen = sizeof (persistent.pubkey);
|
||||
memcpy (discResp.pubkey, persistent.pubkey, discResp.pubkeyLen);
|
||||
discResp.snr = stats.lastSNR; // hopefully the correct one
|
||||
|
||||
sendDiscoverResponse (&discResp);
|
||||
MESH_LOGD(TAG, "Replying to a discover request with tag %d", discResp.tag);
|
||||
}
|
||||
|
||||
} else if (type == CONTROL_DATA_FLAG_DISCOVER_RESP) {
|
||||
DiscoverResponsePayload discResp;
|
||||
discResp.nodeType = frame->payload[index++] & 0x0F;
|
||||
|
||||
discResp.snr = frame->payload[index++];
|
||||
|
||||
discResp.tag = frame->payload[index++];
|
||||
discResp.tag |= frame->payload[index++] << 8;
|
||||
discResp.tag |= frame->payload[index++] << 16;
|
||||
discResp.tag |= frame->payload[index++] << 24;
|
||||
|
||||
uint8_t remainingLen = frame->payloadLen - index;
|
||||
|
||||
uint8_t pubKeyLen = (remainingLen > 8) ? sizeof (discResp.pubkey) : 8;
|
||||
discResp.pubkeyLen = pubKeyLen;
|
||||
memcpy (discResp.pubkey, &(frame->payload[index]), discResp.pubkeyLen);
|
||||
index += pubKeyLen;
|
||||
printDiscoverResponse (&discResp);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,14 @@
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
void decodeControlFrame(FrameStruct frame);
|
||||
void sendDiscoverRequest(const DiscoverRequestPayload *discReq);
|
||||
|
||||
void sendDiscoverResponse(const DiscoverResponsePayload *discResp);
|
||||
|
||||
void printDiscoverRequest(const DiscoverRequestPayload *p);
|
||||
|
||||
void printDiscoverResponse(const DiscoverResponsePayload *p);
|
||||
|
||||
void decodeControlFrame(const FrameStruct * frame);
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "lib/config.h"
|
||||
#include "lib/telemetry/telemetry.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packets/ack.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
@@ -10,6 +11,9 @@
|
||||
#include "encrypted.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "lib/adc/temperature.h"
|
||||
|
||||
#define TICKS_TO_MS(xTicks) (((uint32_t)(xTicks)*1000U) / (uint32_t)configTICK_RATE_HZ)
|
||||
|
||||
|
||||
#define TAG "EncryptedMessage"
|
||||
@@ -20,7 +24,7 @@ void sendEncryptedFrame (NodeEntry *targetNode, uint8_t payloadType, const uint8
|
||||
|
||||
// 1. Header
|
||||
frame.header =
|
||||
ROUTE_TYPE_FLOOD | //currently flood
|
||||
(targetNode->path.pathLen > 0 ? ROUTE_TYPE_DIRECT : ROUTE_TYPE_FLOOD) | // currently flood
|
||||
payloadType |
|
||||
PAYLOAD_VERSION_0;
|
||||
|
||||
@@ -45,22 +49,22 @@ void sendEncryptedFrame (NodeEntry *targetNode, uint8_t payloadType, const uint8
|
||||
memcpy (&frame.path, &targetNode->path, sizeof (frame.path));
|
||||
|
||||
hexdump ("Encrypted frame", frame.payload, frame.payloadLen);
|
||||
sendFrame (frame);
|
||||
LoRaTransmit (&frame);
|
||||
}
|
||||
|
||||
void sendEncryptedTextMessage (NodeEntry *targetNode, const PlainTextMessagePayload *msg) {
|
||||
if (targetNode == NULL) {
|
||||
ESP_LOGW(TAG, "Node is null");
|
||||
MESH_LOGW (TAG, "Node is null");
|
||||
return;
|
||||
}
|
||||
if (targetNode->last_seen_lt == 0) {
|
||||
ESP_LOGW(TAG, "Node is not populated");
|
||||
MESH_LOGW (TAG, "Node is not populated");
|
||||
return;
|
||||
}
|
||||
uint8_t buf[256];
|
||||
uint8_t index = 0;
|
||||
|
||||
uint8_t msgLen = strlen(msg->message) + 1;
|
||||
uint8_t msgLen = strlen (msg->message) + 1;
|
||||
buf[index++] = msg->timestamp;
|
||||
buf[index++] = msg->timestamp >> 8;
|
||||
buf[index++] = msg->timestamp >> 16;
|
||||
@@ -80,12 +84,13 @@ void sendEncryptedResponse (NodeEntry *targetNode, const Response *resp) {
|
||||
uint8_t buf[256];
|
||||
uint8_t index = 0;
|
||||
|
||||
buf[index++] = resp->tag;
|
||||
buf[index++] = resp->tag >> 8;
|
||||
buf[index++] = resp->tag >> 16;
|
||||
buf[index++] = resp->tag >> 24;
|
||||
buf[index++] = (resp->tag) & 0xFF;
|
||||
buf[index++] = (resp->tag >> 8) & 0xFF;
|
||||
buf[index++] = (resp->tag >> 16) & 0xFF;
|
||||
buf[index++] = (resp->tag >> 24) & 0xFF;
|
||||
|
||||
memcpy (&buf[index], resp->data, resp->dataLen);
|
||||
memcpy (&(buf[index]), resp->data, resp->dataLen);
|
||||
index += resp->dataLen;
|
||||
|
||||
sendEncryptedFrame (
|
||||
targetNode,
|
||||
@@ -104,7 +109,8 @@ void sendEncryptedRequest (NodeEntry *targetNode, const Request *req) {
|
||||
buf[index++] = req->timestamp >> 24;
|
||||
|
||||
buf[index++] = req->requestType;
|
||||
memcpy (&buf[index], req->data, req->dataLen);
|
||||
memcpy (&(buf[index]), req->data, req->dataLen);
|
||||
index += req->dataLen;
|
||||
|
||||
sendEncryptedFrame (
|
||||
targetNode,
|
||||
@@ -123,7 +129,7 @@ void sendEncryptedPathPayload (NodeEntry *targetNode, const ReturnedPathPayload
|
||||
|
||||
buf[index++] = path->extra.type;
|
||||
memcpy (&buf[index], path->extra.data,
|
||||
sizeof (path->extra.data));
|
||||
path->extra.dataLen);
|
||||
|
||||
sendEncryptedFrame (
|
||||
targetNode,
|
||||
@@ -137,20 +143,14 @@ void printRequest (const Request *req) {
|
||||
printf (" Timestamp: %u\n", req->timestamp);
|
||||
printf (" Type: 0x%02X\n", req->requestType);
|
||||
printf (" Data: ");
|
||||
for (int i = 0; i < req->dataLen; i++) {
|
||||
printf ("%02X ", req->data[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
hexdump (" Data", req->data, req->dataLen);
|
||||
}
|
||||
|
||||
void printResponse (const Response *resp) {
|
||||
printf ("Response:\n");
|
||||
printf (" Tag: %u\n", resp->tag);
|
||||
printf (" Data: ");
|
||||
for (int i = 0; i < resp->dataLen; i++) {
|
||||
printf ("%02X ", resp->data[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
hexdump (" Data", resp->data, resp->dataLen);
|
||||
}
|
||||
|
||||
void printPlainTextMessage (const PlainTextMessagePayload *msg) {
|
||||
@@ -165,16 +165,10 @@ void printReturnedPathPayload (const ReturnedPathPayload *path) {
|
||||
printf ("ReturnedPathPayload:\n");
|
||||
printf (" Path Length: %u\n", path->path.pathLen);
|
||||
printf (" Path: ");
|
||||
for (int i = 0; i < path->path.pathLen; i++) {
|
||||
printf ("%02X ", path->path.path[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
hexdump (" Path:", path->path.path, path->path.pathLen);
|
||||
printf (" Extra Type: %u\n", path->extra.type);
|
||||
printf (" Extra Data: ");
|
||||
for (int i = 0; i < sizeof (path->extra.data); i++) {
|
||||
printf ("%02X ", path->extra.data[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
hexdump (" Extra data:", path->extra.data, path->extra.dataLen);
|
||||
}
|
||||
|
||||
void printEncryptedPayload (const EncryptedPayloadStruct *enc) {
|
||||
@@ -191,22 +185,22 @@ void printEncryptedPayload (const EncryptedPayloadStruct *enc) {
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
EncryptedPayloadStruct decodeEncryptedPayload (FrameStruct frame) {
|
||||
void decodeEncryptedPayload (const FrameStruct *frame) {
|
||||
EncryptedPayloadStruct enc;
|
||||
memset (&enc, 0, sizeof (enc));
|
||||
enc.type = frame.header & PAYLOAD_TYPE_MASK;
|
||||
enc.type = frame->header & PAYLOAD_TYPE_MASK;
|
||||
unsigned char index = 0;
|
||||
|
||||
enc.destinationHash = frame.payload[index++];
|
||||
enc.sourceHash = frame.payload[index++];
|
||||
enc.cipherMAC = frame.payload[index];
|
||||
enc.cipherMAC |= frame.payload[index + 1] << 8;
|
||||
enc.destinationHash = frame->payload[index++];
|
||||
enc.sourceHash = frame->payload[index++];
|
||||
enc.cipherMAC = frame->payload[index];
|
||||
enc.cipherMAC |= frame->payload[index + 1] << 8;
|
||||
|
||||
if (enc.destinationHash != persistent.pubkey[0]) {
|
||||
return enc;
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Finding remote node, sourceHash is %d", enc.sourceHash);
|
||||
MESH_LOGI (TAG, "Finding remote node, sourceHash is %d", enc.sourceHash);
|
||||
|
||||
NodeEntry *remNode = getNode (enc.sourceHash);
|
||||
|
||||
@@ -214,96 +208,152 @@ EncryptedPayloadStruct decodeEncryptedPayload (FrameStruct frame) {
|
||||
|
||||
|
||||
if (remNode == NULL) {
|
||||
ESP_LOGW(TAG, "Node not in DB");
|
||||
return enc;
|
||||
MESH_LOGW (TAG, "Node not in DB");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Found node with index %d", remNode - persistent.contacts);
|
||||
MESH_LOGI (TAG, "Found node with index %d", remNode - persistent.contacts);
|
||||
|
||||
|
||||
if (mac_then_decrypt (remNode->secret, 32, &(frame.payload[index]), frame.payloadLen - index, enc.payload) != 0) {
|
||||
ESP_LOGW (TAG, "HMAC failed on encrypted message %s", remNode->name);
|
||||
if (mac_then_decrypt (remNode->secret, 32, &(frame->payload[index]), frame->payloadLen - index, enc.payload) != 0) {
|
||||
MESH_LOGW (TAG, "HMAC failed on encrypted message %s", remNode->name);
|
||||
} else {
|
||||
enc.payloadLen = frame.payloadLen - HMAC_SIZE;
|
||||
ESP_LOGI(TAG, "HMAC success from %s, %u bytes long", remNode->name, enc.payloadLen);
|
||||
sendDiscreteAck(enc.payload, 5 + strlen((char *)&enc.payload[5]), remNode->pubKey);
|
||||
enc.payloadLen = frame->payloadLen - HMAC_SIZE;
|
||||
MESH_LOGI (TAG, "HMAC success from %s, %u bytes long", remNode->name, enc.payloadLen);
|
||||
sendDiscreteAck (enc.payload, 5 + strlen ((char *)&enc.payload[5]), remNode->pubKey);
|
||||
}
|
||||
|
||||
return enc;
|
||||
printf (" Typexdd: 0x%02X\n", enc.type);
|
||||
if (enc.payloadLen > 0) {
|
||||
parseEncryptedPayload (&enc);
|
||||
}
|
||||
}
|
||||
|
||||
void parseEncryptedPayload (EncryptedPayloadStruct enc) {
|
||||
void parseEncryptedPayload (const EncryptedPayloadStruct *enc) {
|
||||
// printEncryptedPayload(&enc);
|
||||
|
||||
printf ("EncryptedPayload:\n");
|
||||
printf (" Type: 0x%02X\n", enc.type);
|
||||
printf (" DestinationHash: 0x%02X\n", enc.destinationHash);
|
||||
printf (" SourceHash: 0x%02X\n", enc.sourceHash);
|
||||
printf (" CipherMAC: 0x%04X\n", enc.cipherMAC);
|
||||
printf (" PayloadLen: %u\n", enc.payloadLen);
|
||||
printf (" Payload: ");
|
||||
hexdump("Full payload buffer", enc.payload, sizeof(enc.payload));
|
||||
printf (" Type: 0x%02X\n", enc->type);
|
||||
printf (" DestinationHash: 0x%02X\n", enc->destinationHash);
|
||||
printf (" SourceHash: 0x%02X\n", enc->sourceHash);
|
||||
printf (" CipherMAC: 0x%04X\n", enc->cipherMAC);
|
||||
printf (" PayloadLen: %u\n", enc->payloadLen);
|
||||
hexdump (" Payload: ", enc->payload, enc->payloadLen);
|
||||
printf ("\n");
|
||||
|
||||
uint8_t index = 0;
|
||||
if (enc.type == PAYLOAD_TYPE_PATH) {
|
||||
if (enc->type == PAYLOAD_TYPE_PATH) {
|
||||
|
||||
ReturnedPathPayload retPath;
|
||||
retPath.path.pathLen = enc.payload[index++];
|
||||
retPath.path.pathLen = enc->payload[index++];
|
||||
if (retPath.path.pathLen > 64) {
|
||||
ESP_LOGW (TAG, "Path too long\n");
|
||||
MESH_LOGW (TAG, "Path too long\n");
|
||||
return;
|
||||
}
|
||||
memcpy (retPath.path.path, &(enc.payload[index]), retPath.path.pathLen);
|
||||
memcpy (retPath.path.path, &(enc->payload[index]), retPath.path.pathLen);
|
||||
index += retPath.path.pathLen;
|
||||
retPath.extra.type = enc.payload[index++];
|
||||
memcpy (retPath.extra.data, &(enc.payload[index]), enc.payloadLen - index);
|
||||
retPath.extra.type = enc->payload[index++];
|
||||
retPath.extra.dataLen = enc->payloadLen - index;
|
||||
memcpy (retPath.extra.data, &(enc->payload[index]), retPath.extra.dataLen);
|
||||
|
||||
} else if (enc.type == PAYLOAD_TYPE_REQ) {
|
||||
} 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;
|
||||
req.requestType = enc.payload[index++];
|
||||
req.dataLen = enc.payloadLen - index;
|
||||
memcpy (req.data, &(enc.payload[index]), req.dataLen);
|
||||
req.timestamp = enc->payload[index++];
|
||||
req.timestamp |= enc->payload[index++] << 8;
|
||||
req.timestamp |= enc->payload[index++] << 16;
|
||||
req.timestamp |= enc->payload[index++] << 24;
|
||||
req.requestType = enc->payload[index++];
|
||||
req.dataLen = enc->payloadLen - index;
|
||||
memcpy (req.data, &(enc->payload[index]), req.dataLen);
|
||||
printRequest (&req);
|
||||
switch (req.requestType) {
|
||||
case REQUEST_GET_STATS: {
|
||||
Response resp;
|
||||
resp.tag = RTC_GetCounter();
|
||||
memcpy(resp.data, &stats, sizeof(stats));
|
||||
resp.dataLen = sizeof(stats);
|
||||
sendEncryptedResponse(enc.remNode, &resp);
|
||||
stats.totalUpTimeSeconds = RTC_GetCounter() - startupTime;
|
||||
stats.totalAirTimeSeconds = TICKS_TO_MS (tickAirtime / 1000);
|
||||
memcpy (resp.data, &stats, sizeof (stats));
|
||||
resp.dataLen = sizeof (stats);
|
||||
sendEncryptedResponse (enc->remNode, &resp);
|
||||
break;
|
||||
}
|
||||
case REQUEST_KEEPALIVE:
|
||||
break;
|
||||
case REQUEST_GET_TELEMETRY_DATA:
|
||||
case REQUEST_GET_TELEMETRY_DATA: {
|
||||
Response resp;
|
||||
resp.tag = req.timestamp;
|
||||
uint8_t index2 = 0;
|
||||
resp.data[index2++] = TELEM_CHANNEL_SELF;
|
||||
resp.data[index2++] = LPP_TEMPERATURE;
|
||||
|
||||
int16_t dataTemp = getDeciTemperature();
|
||||
|
||||
printf ("The temperature is %d decicelsius\n", dataTemp);
|
||||
|
||||
resp.data[index2++] = (dataTemp >> 8) & 0xFF;
|
||||
|
||||
resp.data[index2++] = dataTemp & 0xFF;
|
||||
|
||||
|
||||
resp.data[index2++] = TELEM_CHANNEL_SELF;
|
||||
resp.data[index2++] = LPP_VOLTAGE;
|
||||
|
||||
int16_t dataVolt = stats.millivolts / 10;
|
||||
|
||||
resp.data[index2++] = (dataVolt >> 8) & 0xFF;
|
||||
|
||||
resp.data[index2++] = dataVolt & 0xFF;
|
||||
|
||||
if (enc->remNode->authenticated) {
|
||||
|
||||
encode_gps (TELEM_CHANNEL_SELF, persistent.latitude / 1000000.0f, persistent.longitude / 1000000.0f, persistent.altitude / 100.0f, &(resp.data[index2]));
|
||||
// encode_gps(TELEM_CHANNEL_SELF, 48.1909f, 17.0303f, 234.0f, &(resp.data[index2]));
|
||||
|
||||
index2 += LPP_GPS_SIZE;
|
||||
}
|
||||
|
||||
if (enc->remNode->authenticated) {
|
||||
|
||||
resp.data[index2++] = 2;
|
||||
resp.data[index2++] = LPP_TEMPERATURE;
|
||||
|
||||
int16_t jokeTemp = 6942;
|
||||
|
||||
resp.data[index2++] = (jokeTemp >> 8) & 0xFF;
|
||||
|
||||
resp.data[index2++] = jokeTemp & 0xFF;
|
||||
|
||||
resp.dataLen = index2;
|
||||
}
|
||||
|
||||
sendEncryptedResponse (enc->remNode, &resp);
|
||||
|
||||
break;
|
||||
}
|
||||
case REQUEST_GET_MIN_MAX_AVG:
|
||||
break;
|
||||
case REQUEST_GET_ACCESS_LIST:
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (enc.type == PAYLOAD_TYPE_RESPONSE) {
|
||||
} else if (enc->type == PAYLOAD_TYPE_RESPONSE) {
|
||||
Response resp;
|
||||
resp.tag = enc.payload[index++];
|
||||
resp.tag |= enc.payload[index++] << 8;
|
||||
resp.tag |= enc.payload[index++] << 16;
|
||||
resp.tag |= enc.payload[index++] << 24;
|
||||
resp.dataLen = enc.payloadLen - index;
|
||||
memcpy (resp.data, &(enc.payload[index]), resp.dataLen);
|
||||
resp.tag = enc->payload[index++];
|
||||
resp.tag |= enc->payload[index++] << 8;
|
||||
resp.tag |= enc->payload[index++] << 16;
|
||||
resp.tag |= enc->payload[index++] << 24;
|
||||
resp.dataLen = enc->payloadLen - index;
|
||||
memcpy (resp.data, &(enc->payload[index]), resp.dataLen);
|
||||
printResponse (&resp);
|
||||
|
||||
} else if (enc.type == PAYLOAD_TYPE_TXT_MSG) {
|
||||
} else if (enc->type == PAYLOAD_TYPE_TXT_MSG) {
|
||||
PlainTextMessagePayload plaintext;
|
||||
plaintext.timestamp = enc.payload[index++];
|
||||
plaintext.timestamp |= enc.payload[index++] << 8;
|
||||
plaintext.timestamp |= enc.payload[index++] << 16;
|
||||
plaintext.timestamp |= enc.payload[index++] << 24;
|
||||
plaintext.attempt = enc.payload[index] & 0x03;
|
||||
plaintext.textType = enc.payload[index++] >> 2;
|
||||
memcpy (plaintext.message, &(enc.payload[index]), enc.payloadLen - index);
|
||||
plaintext.timestamp = enc->payload[index++];
|
||||
plaintext.timestamp |= enc->payload[index++] << 8;
|
||||
plaintext.timestamp |= enc->payload[index++] << 16;
|
||||
plaintext.timestamp |= enc->payload[index++] << 24;
|
||||
plaintext.attempt = enc->payload[index] & 0x03;
|
||||
plaintext.textType = enc->payload[index++] >> 2;
|
||||
memcpy (plaintext.message, &(enc->payload[index]), enc->payloadLen - index);
|
||||
printPlainTextMessage (&plaintext);
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ void sendEncryptedRequest (NodeEntry *targetNode, const Request *req);
|
||||
|
||||
void sendEncryptedPathPayload (NodeEntry *targetNode, const ReturnedPathPayload *path);
|
||||
|
||||
EncryptedPayloadStruct decodeEncryptedPayload (FrameStruct frame);
|
||||
void decodeEncryptedPayload (const FrameStruct *frame);
|
||||
|
||||
void parseEncryptedPayload (EncryptedPayloadStruct enc);
|
||||
void parseEncryptedPayload (const EncryptedPayloadStruct * enc);
|
||||
|
||||
#endif
|
||||
@@ -9,61 +9,64 @@
|
||||
|
||||
#define TAG "GroupMessage"
|
||||
|
||||
void sendGroupMessage (GroupTextMessage msg) {
|
||||
|
||||
msg.channelHash = persistent.aesKeys[msg.keyIndex][0];
|
||||
|
||||
msg.flags = 0;
|
||||
msg.timestamp = RTC_GetCounter();
|
||||
void sendGroupMessage (const GroupTextMessage *msg) {
|
||||
// Prepare values locally instead of modifying msg
|
||||
uint8_t channelHash = persistent.aesKeys[msg->keyIndex][0];
|
||||
uint8_t flags = 0;
|
||||
int32_t timestamp = RTC_GetCounter();
|
||||
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_GRP_TXT | PAYLOAD_VERSION_0;
|
||||
frame.path.pathLen = 0;
|
||||
size_t offset = 0;
|
||||
memset (frame.payload, 0, sizeof (frame.payload));
|
||||
frame.payload[offset++] = msg.channelHash;
|
||||
frame.payload[offset++] = channelHash;
|
||||
|
||||
uint8_t cipherBuf[176];
|
||||
size_t offset2 = 0;
|
||||
memcpy (cipherBuf, (const void *)&(msg.timestamp), 4);
|
||||
offset2 += 4;
|
||||
cipherBuf[offset2++] = msg.flags;
|
||||
size_t textSize = offset2 + strlen ((const char *)msg.text);
|
||||
if (textSize > 175) {
|
||||
textSize = 175;
|
||||
// Build encryption buffer directly on stack (no extra large buffer)
|
||||
uint8_t buf[180]; // enough for timestamp + flags + text
|
||||
size_t buf_offset = 0;
|
||||
|
||||
memcpy (buf + buf_offset, ×tamp, sizeof (timestamp));
|
||||
buf_offset += sizeof (timestamp);
|
||||
|
||||
buf[buf_offset++] = flags;
|
||||
|
||||
size_t textLen = strlen ((const char *)msg->text);
|
||||
if (buf_offset + textLen > sizeof (buf)) {
|
||||
textLen = sizeof (buf) - buf_offset;
|
||||
}
|
||||
memcpy (cipherBuf + offset2, msg.text, textSize);
|
||||
offset2 += textSize;
|
||||
memcpy (buf + buf_offset, msg->text, textLen);
|
||||
buf_offset += textLen;
|
||||
|
||||
hexdump ("TxDumpDec", buf, buf_offset);
|
||||
|
||||
// Encrypt and MAC directly into frame payload after channelHash
|
||||
size_t olen = 0;
|
||||
hexdump ("TxDumpDec", cipherBuf, offset2);
|
||||
encrypt_then_mac (&(persistent.aesKeys[msg.keyIndex][1]), 16, cipherBuf, offset2, &(frame.payload[offset]), &olen);
|
||||
encrypt_then_mac (&persistent.aesKeys[msg->keyIndex][1], 16, buf, buf_offset, &frame.payload[offset], &olen);
|
||||
|
||||
frame.payloadLen = olen + 1;
|
||||
frame.payloadLen = olen + 1; // +1 for channelHash
|
||||
|
||||
sendFrame (frame);
|
||||
return;
|
||||
LoRaTransmit (&frame);
|
||||
}
|
||||
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex) {
|
||||
GroupTextMessage msg;
|
||||
strcpy((char *) msg.text, persistent.nodeName);
|
||||
strcpy ((char *)msg.text, persistent.nodeName);
|
||||
strcat ((char *)msg.text, ": ");
|
||||
strcat ((char *)msg.text, txt);
|
||||
msg.keyIndex = keyIndex;
|
||||
sendGroupMessage (msg);
|
||||
sendGroupMessage (&msg);
|
||||
return;
|
||||
}
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame) {
|
||||
void decodeGroupMessage (const FrameStruct *frame) {
|
||||
GroupTextMessage msg;
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
|
||||
ESP_LOGW (TAG, "Not a group text");
|
||||
return msg;
|
||||
if ((frame->header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
|
||||
MESH_LOGW (TAG, "Not a group text");
|
||||
return;
|
||||
}
|
||||
unsigned char index = 0;
|
||||
msg.channelHash = frame.payload[index++];
|
||||
msg.channelHash = frame->payload[index++];
|
||||
unsigned char tmp[184];
|
||||
|
||||
|
||||
@@ -71,27 +74,27 @@ GroupTextMessage decodeGroupMessage (FrameStruct frame) {
|
||||
for (unsigned char i = 0; i < AESKeyCount; i++) {
|
||||
|
||||
if (msg.channelHash != persistent.aesKeys[i][0]) {
|
||||
ESP_LOGW (TAG, "Hash %d does not equal %d", persistent.aesKeys[i][0], msg.channelHash);
|
||||
MESH_LOGW (TAG, "Hash %d does not equal %d", persistent.aesKeys[i][0], msg.channelHash);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGW (TAG, "Hash does equal %d", msg.channelHash);
|
||||
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) {
|
||||
ESP_LOGW (TAG, "HMAC failed on grouphash key %d not matching %d", persistent.aesKeys[i][0], 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);
|
||||
hexdump ("RxDumpDec", tmp, frame->payloadLen - index);
|
||||
decrypted = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!decrypted) {
|
||||
return msg;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char plaintextLen = frame.payloadLen - index;
|
||||
unsigned char plaintextLen = frame->payloadLen - index;
|
||||
index = 0;
|
||||
|
||||
memcpy (&msg.timestamp, tmp + index, 4);
|
||||
@@ -99,10 +102,11 @@ GroupTextMessage decodeGroupMessage (FrameStruct frame) {
|
||||
msg.flags = tmp[index++];
|
||||
|
||||
memcpy (msg.text, tmp + index, plaintextLen - index);
|
||||
return msg;
|
||||
|
||||
printGroupMessage (&msg);
|
||||
}
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg) {
|
||||
printf ("Message with channel hash %d, flags %d: %s\n", msg.channelHash,
|
||||
msg.flags, msg.text);
|
||||
void printGroupMessage (const GroupTextMessage *msg) {
|
||||
printf ("Message with channel hash %d, flags %d: %s\n", msg->channelHash,
|
||||
msg->flags, msg->text);
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
#include "stdint.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
void sendGroupMessage (GroupTextMessage msg);
|
||||
void sendGroupMessage (const GroupTextMessage * msg);
|
||||
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex);
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame);
|
||||
void decodeGroupMessage (const FrameStruct * frame);
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg);
|
||||
void printGroupMessage (const GroupTextMessage * msg);
|
||||
|
||||
#endif
|
||||
@@ -56,6 +56,7 @@ typedef struct DiscoverResponsePayload {
|
||||
int8_t snr;
|
||||
uint32_t tag;
|
||||
uint8_t pubkey[32];
|
||||
uint8_t pubkeyLen;
|
||||
} DiscoverResponsePayload;
|
||||
|
||||
typedef struct AnonymousRequestPayload {
|
||||
@@ -116,6 +117,27 @@ typedef struct Node {
|
||||
char flags;
|
||||
} Node;
|
||||
|
||||
typedef struct {
|
||||
char name[32];
|
||||
unsigned char pubKey[32];
|
||||
unsigned char secret[32];
|
||||
|
||||
int32_t gps_latitude;
|
||||
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 sync_timestamp;
|
||||
} NodeEntry;
|
||||
|
||||
typedef struct EncryptedPayloadStruct {
|
||||
uint8_t destinationHash;
|
||||
uint8_t sourceHash;
|
||||
@@ -153,6 +175,7 @@ typedef struct AdvertisementPayload {
|
||||
uint8_t pubKey[32];
|
||||
int32_t timestamp;
|
||||
uint8_t signature[64];
|
||||
uint8_t valid;
|
||||
uint8_t dataFlags;
|
||||
int32_t latitude;
|
||||
int32_t longitude;
|
||||
@@ -164,6 +187,7 @@ typedef struct AdvertisementPayload {
|
||||
|
||||
typedef struct Extra {
|
||||
uint8_t type;
|
||||
uint8_t dataLen;
|
||||
uint8_t data[180]; // hopefully long enough
|
||||
} Extra;
|
||||
|
||||
@@ -204,4 +228,8 @@ typedef struct RepeaterStats {
|
||||
uint32_t total_rx_air_time_secs;
|
||||
} RepeaterStats;
|
||||
|
||||
typedef struct Channel {
|
||||
|
||||
} Channel;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "stats.h"
|
||||
|
||||
RepeaterStats stats;
|
||||
RepeaterStats stats;
|
||||
|
||||
uint32_t startupTime = 0;
|
||||
uint32_t tickAirtime = 0;
|
||||
@@ -4,4 +4,8 @@
|
||||
|
||||
extern RepeaterStats stats;
|
||||
|
||||
extern uint32_t startupTime;
|
||||
|
||||
extern uint32_t tickAirtime;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user