#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) { FrameStruct frame; memset (&frame, 0, sizeof (frame)); unsigned char index = 0; frame.header = data[index++]; if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT || (frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) { memcpy (frame.transportCodes, data + index, 4); index += 4; } frame.path.pathLen = data[index++]; memcpy (frame.path.path, data + index, frame.path.pathLen); index += frame.path.pathLen; frame.payloadLen = dataLen - index; memcpy (frame.payload, data + index, frame.payloadLen); return frame; } */ void printFrameHeader (const FrameStruct *frame) { switch (frame->header & ROUTE_TYPE_MASK) { case ROUTE_TYPE_TRANSPORT_FLOOD: printf ("transport flood"); break; case ROUTE_TYPE_FLOOD: printf ("flood"); break; case ROUTE_TYPE_DIRECT: printf ("direct"); break; case ROUTE_TYPE_TRANSPORT_DIRECT: printf ("transport direct"); break; } printf (", payload type is "); switch (frame->header & PAYLOAD_TYPE_MASK) { case PAYLOAD_TYPE_REQ: printf ("request"); break; case PAYLOAD_TYPE_RESPONSE: printf ("response"); break; case PAYLOAD_TYPE_TXT_MSG: printf ("text message"); break; case PAYLOAD_TYPE_ACK: printf ("acknowledgement"); break; case PAYLOAD_TYPE_ADVERT: printf ("advert"); break; case PAYLOAD_TYPE_GRP_TXT: printf ("group text"); break; case PAYLOAD_TYPE_GRP_DATA: printf ("group data"); break; case PAYLOAD_TYPE_ANON_REQ: printf ("anon request"); break; case PAYLOAD_TYPE_PATH: printf ("path"); break; case PAYLOAD_TYPE_TRACE: printf ("trace"); break; case PAYLOAD_TYPE_MULTIPART: printf ("multipart"); break; case PAYLOAD_TYPE_CONTROL: printf ("control"); break; case PAYLOAD_TYPE_RAW_CUSTOM: printf ("raw"); break; } char version[2]; 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]))); } 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]); } putchar ('\n'); } void LoRaTransmit (const FrameStruct *frame) { uint8_t len = 2; // header + path_len if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT || (frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) { len += 4; } len += frame->path.pathLen; len += frame->payloadLen; uint16_t irqStatus; char rv = 0; if (txActive == 0) { txActive = 1; if (PacketParams[2] == 0x00) { // explicit header, variable length PacketParams[3] = len; } WriteCommand (SX126X_CMD_SET_PACKET_PARAMS, PacketParams, 6); ClearIrqStatus (SX126X_IRQ_ALL); WaitForIdle (BUSY_WAIT, "start WriteBuffer", 1); uint8_t cmdBuf[2] = {SX126X_CMD_WRITE_BUFFER, 0x00}; uint8_t cmdLen = sizeof (cmdBuf); 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 (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) { /* -------- 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]; LoRaTransmit (frame); } } /* -------- 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); } } } } // Verify MAC + Decrypt int encrypt_then_mac (const uint8_t *aes_key, const uint8_t keySize, const uint8_t *plaintext, size_t plen, uint8_t *output, size_t *olen) { if (plen == 0) return -1; size_t padded_len = ((plen + 15) / 16) * 16; // prepare padded buffer uint8_t padded[padded_len]; 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; // encrypt plaintext aes_encrypt_ecb (aes_key, 16, padded, padded_len, ciphertext); // compute HMAC over ciphertext uint8_t mac[32]; // full SHA-256 hmac_sha256 (aes_key, keySize, ciphertext, padded_len, mac); // copy only HMAC_SIZE bytes of MAC memcpy (output, mac, HMAC_SIZE); // return total length = HMAC + ciphertext *olen = HMAC_SIZE + padded_len; return 0; } int mac_then_decrypt (const uint8_t *aes_key, const uint8_t keySize, const uint8_t *input, size_t ilen, uint8_t *plaintext) { if (ilen <= HMAC_SIZE) return -1; const uint8_t *mac = input; 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 uint8_t calc_mac[32]; // full SHA-256 hmac_sha256 (aes_key, keySize, ciphertext, clen, calc_mac); if (memcmp (mac, calc_mac, HMAC_SIZE) != 0) 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; }