mirror of
https://github.com/ruvnet/RuView.git
synced 2026-08-31 12:36:09 +00:00
125 lines
4.7 KiB
C
125 lines
4.7 KiB
C
/** @file channel_sounding_protocol.c */
|
|
|
|
#include "channel_sounding_protocol.h"
|
|
|
|
#ifdef ESP_PLATFORM
|
|
#include "mbedtls/constant_time.h"
|
|
#endif
|
|
|
|
static uint16_t read_le16(const uint8_t *p)
|
|
{
|
|
return (uint16_t)p[0] | ((uint16_t)p[1] << 8);
|
|
}
|
|
|
|
static uint32_t read_le32(const uint8_t *p)
|
|
{
|
|
return (uint32_t)p[0]
|
|
| ((uint32_t)p[1] << 8)
|
|
| ((uint32_t)p[2] << 16)
|
|
| ((uint32_t)p[3] << 24);
|
|
}
|
|
|
|
uint32_t rv_cs_crc32(const uint8_t *data, size_t len)
|
|
{
|
|
if (data == NULL) return 0u;
|
|
uint32_t crc = 0xffffffffu;
|
|
for (size_t i = 0u; i < len; i++) {
|
|
crc ^= data[i];
|
|
for (unsigned bit = 0u; bit < 8u; bit++) {
|
|
uint32_t mask = (uint32_t)-(int32_t)(crc & 1u);
|
|
crc = (crc >> 1) ^ (0xedb88320u & mask);
|
|
}
|
|
}
|
|
return ~crc;
|
|
}
|
|
|
|
bool rv_cs_sequence_is_newer(uint32_t candidate, uint32_t previous)
|
|
{
|
|
uint32_t delta = candidate - previous;
|
|
return delta != 0u && delta < 0x80000000u;
|
|
}
|
|
|
|
rv_cs_parse_result_t rv_cs_parse_frame(const uint8_t *data,
|
|
size_t len,
|
|
uint32_t max_age_us,
|
|
uint16_t min_quality_permille,
|
|
rv_cs_measurement_t *out)
|
|
{
|
|
if (data == NULL || out == NULL) return RV_CS_PARSE_BAD_ARGUMENT;
|
|
if (len != RV_CS_FRAME_SIZE) return RV_CS_PARSE_BAD_LENGTH;
|
|
if (read_le32(&data[0]) != RV_CS_MAGIC) return RV_CS_PARSE_BAD_MAGIC;
|
|
if (data[4] != RV_CS_VERSION) return RV_CS_PARSE_BAD_VERSION;
|
|
if (data[7] != 0u || read_le16(&data[8]) != RV_CS_FRAME_SIZE) return RV_CS_PARSE_BAD_LENGTH;
|
|
if ((data[5] & ~RV_CS_FLAGS_ALLOWED) != 0u) return RV_CS_PARSE_BAD_FLAGS;
|
|
if (rv_cs_crc32(data, RV_CS_FRAME_SIZE - 4u)
|
|
!= read_le32(&data[RV_CS_FRAME_SIZE - 4u])) {
|
|
return RV_CS_PARSE_BAD_CRC;
|
|
}
|
|
|
|
rv_cs_measurement_t parsed = {
|
|
.flags = data[5],
|
|
.key_id = data[6],
|
|
.channel_index = read_le16(&data[10]),
|
|
.sequence = read_le32(&data[12]),
|
|
.sample_age_us = read_le32(&data[16]),
|
|
.source_id = read_le32(&data[20]),
|
|
.quality_permille = read_le16(&data[24]),
|
|
.timing_uncertainty_us = read_le16(&data[26]),
|
|
.phase_millirad = (int32_t)read_le32(&data[28]),
|
|
.rtt_picoseconds = (int32_t)read_le32(&data[32]),
|
|
.frequency_offset_hz = (int32_t)read_le32(&data[36]),
|
|
.source_session_id = read_le32(&data[40]),
|
|
.procedure_id = read_le32(&data[44]),
|
|
.step_index = read_le16(&data[48]),
|
|
.step_count = read_le16(&data[50]),
|
|
};
|
|
|
|
if (parsed.source_id == 0u) return RV_CS_PARSE_BAD_SOURCE;
|
|
if (parsed.source_session_id == 0u) return RV_CS_PARSE_BAD_SESSION;
|
|
if (parsed.procedure_id == 0u) return RV_CS_PARSE_BAD_PROCEDURE;
|
|
if (parsed.step_count < RV_CS_MIN_STEP_COUNT
|
|
|| parsed.step_count > RV_CS_MAX_STEP_COUNT
|
|
|| parsed.step_index >= parsed.step_count) return RV_CS_PARSE_BAD_STEP;
|
|
if (parsed.channel_index > RV_CS_MAX_CHANNEL_INDEX) return RV_CS_PARSE_BAD_CHANNEL;
|
|
if (parsed.quality_permille < min_quality_permille
|
|
|| parsed.quality_permille > 1000u) return RV_CS_PARSE_BAD_QUALITY;
|
|
if (parsed.phase_millirad < -RV_CS_MAX_PHASE_MRAD
|
|
|| parsed.phase_millirad > RV_CS_MAX_PHASE_MRAD) return RV_CS_PARSE_BAD_PHASE;
|
|
if (parsed.rtt_picoseconds < 0
|
|
|| parsed.rtt_picoseconds > RV_CS_MAX_RTT_PS) return RV_CS_PARSE_BAD_RTT;
|
|
if (parsed.frequency_offset_hz < -RV_CS_MAX_FREQ_OFFSET_HZ
|
|
|| parsed.frequency_offset_hz > RV_CS_MAX_FREQ_OFFSET_HZ) {
|
|
return RV_CS_PARSE_BAD_FREQUENCY_OFFSET;
|
|
}
|
|
if (parsed.timing_uncertainty_us > 10000u) return RV_CS_PARSE_BAD_TIMING_UNCERTAINTY;
|
|
if (parsed.sample_age_us > max_age_us) return RV_CS_PARSE_STALE;
|
|
*out = parsed;
|
|
return RV_CS_PARSE_OK;
|
|
}
|
|
|
|
void rv_cs_mac_input(const uint8_t frame[RV_CS_FRAME_SIZE],
|
|
uint8_t out[RV_CS_MAC_INPUT_SIZE])
|
|
{
|
|
static const uint8_t domain[RV_CS_MAC_DOMAIN_SIZE] = {
|
|
'R', 'u', 'V', 'i', 'e', 'w', '/', 'C', 'S', '/', 'v', '1'
|
|
};
|
|
if (frame == NULL || out == NULL) return;
|
|
for (size_t i = 0u; i < sizeof(domain); i++) out[i] = domain[i];
|
|
for (size_t i = 0u; i < RV_CS_SIGNED_PREFIX_SIZE; i++) {
|
|
out[sizeof(domain) + i] = frame[i];
|
|
}
|
|
}
|
|
|
|
bool rv_cs_auth_tag_equal(const uint8_t lhs[RV_CS_AUTH_TAG_SIZE],
|
|
const uint8_t rhs[RV_CS_AUTH_TAG_SIZE])
|
|
{
|
|
if (lhs == NULL || rhs == NULL) return false;
|
|
#ifdef ESP_PLATFORM
|
|
return mbedtls_ct_memcmp(lhs, rhs, RV_CS_AUTH_TAG_SIZE) == 0;
|
|
#else
|
|
uint8_t diff = 0u;
|
|
for (size_t i = 0u; i < RV_CS_AUTH_TAG_SIZE; i++) diff |= (uint8_t)(lhs[i] ^ rhs[i]);
|
|
return diff == 0u;
|
|
#endif
|
|
}
|