1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-06-27 14:03:24 -04:00
Files
sdrangel/modemmeshcore/meshcore_decoder.h
T

114 lines
4.6 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2026 Tom Hensel <code@jitter.eu> //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// MeshCore wire-packet decoder. Inverse of meshcore_builders. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef MODEMMESHCORE_MESHCORE_DECODER_H_
#define MODEMMESHCORE_MESHCORE_DECODER_H_
#include <QByteArray>
#include <QString>
#include <QVector>
#include "export.h"
#include "meshcorepacket.h"
namespace modemmeshcore
{
namespace decoder
{
// Parsed envelope header (fields populated from the first 1+optional-4+1+N
// bytes on the wire).
struct ParsedHeader
{
uint8_t routeType = 0;
uint8_t payloadType = 0;
uint8_t version = 0;
bool hasTransport = false;
int pathLenByte = 0; // raw path_len byte
int payloadOffset = 0; // byte offset into the wire packet at which
// the payload-type-specific body begins
};
// Returns true on success, false if the wire packet is too short or
// malformed. Populates hdr.
MODEMMESHCORE_API bool parseHeader(const QByteArray& wire, ParsedHeader& hdr);
// Key spec list — the keys an operator has loaded for the RX side. Used by
// Packet::decodeFrame to trial-decrypt incoming encrypted frames.
//
// String format (case-insensitive keys, semicolon-separated entries):
// identity=<hex64> our 32-byte Ed25519 seed
// contact:<name>=<hex64> a known peer's 32-byte Ed25519 pubkey
// channel:<name>=<hex16|hex32|name=public> a group channel PSK
//
// Example:
// identity=01..20; contact:alice=ab..cd; channel:public=8b3387e9...cd72
struct KeySpec
{
enum Kind { Identity, Contact, Channel };
Kind kind = Identity;
QString name; // identifier (empty for Identity, non-empty for Contact/Channel)
QByteArray data; // raw bytes
};
// Parse the key spec list. Returns true on success. Sets error on failure.
// If validateOnly, don't store data into outKeys.
MODEMMESHCORE_API bool parseKeySpecList(
const QString& spec,
QVector<KeySpec>& outKeys,
QString& error,
bool validateOnly = false);
// ---- per-payload decoders -----------------------------------------------------
// ADVERT (no key needed). Populates fields:
// advert.pubkey (hex)
// advert.timestamp
// advert.flags
// advert.name (if HasName flag set)
// advert.lat / advert.lon (if HasLocation flag set)
// advert.signature_valid (Ed25519 verify)
MODEMMESHCORE_API bool decodeAdvert(const QByteArray& wire, const ParsedHeader& hdr, DecodeResult& out);
// ACK (no key needed). Populates:
// ack.dest_hash (hex 1 byte)
// ack.msg_hash (hex 4 bytes)
MODEMMESHCORE_API bool decodeAck(const QByteArray& wire, const ParsedHeader& hdr, DecodeResult& out);
// TXT_MSG. Trial-decrypts against (identity, contact pubkey) pairs.
// On success: txt.text, txt.sender_pubkey (hex), txt.timestamp, txt.txt_type
// Always populates: txt.dest_hash, txt.src_hash
MODEMMESHCORE_API bool decodeTxtMsg(const QByteArray& wire,
const ParsedHeader& hdr,
const QVector<KeySpec>& keys,
DecodeResult& out);
// GRP_TXT. Trial-decrypts against channel PSKs.
// On success: grp.text, grp.channel, grp.timestamp, grp.txt_type
// Always: grp.channel_hash
MODEMMESHCORE_API bool decodeGrpTxt(const QByteArray& wire,
const ParsedHeader& hdr,
const QVector<KeySpec>& keys,
DecodeResult& out);
// ANON_REQ. Decrypts using identity + sender pubkey embedded in the packet.
// On success: anon.text/data, anon.sender_pubkey, anon.timestamp
// Always: anon.dest_hash
MODEMMESHCORE_API bool decodeAnonReq(const QByteArray& wire,
const ParsedHeader& hdr,
const QVector<KeySpec>& keys,
DecodeResult& out);
} // namespace decoder
} // namespace modemmeshcore
#endif // MODEMMESHCORE_MESHCORE_DECODER_H_