Files
root ca13734bf0 Add full automotive RTOS project
Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
2026-08-23 03:35:29 -04:00

281 lines
7.0 KiB
C

/**
* @file e2e_protection.c
* @brief End-to-End Protection for safety-critical communication
*/
#include "kernel.h"
#include "can_driver.h"
#include <string.h>
/* E2E Protection Configuration */
#define E2E_MAX_PROFILES 8
#define E2E_MAX_DATA_LENGTH 64
#define E2E_CRC_POLYNOMIAL 0x2F /* CRC-8 polynomial */
/* E2E Profile Types */
typedef enum {
E2E_PROFILE_1 = 1, /* CRC-8 */
E2E_PROFILE_2 = 2, /* CRC-16 */
E2E_PROFILE_4 = 4, /* CRC-32 */
E2E_PROFILE_5 = 5, /* Custom */
E2E_PROFILE_7 = 7 /* Counter + CRC */
} E2eProfileType_t;
/* E2E Configuration */
typedef struct {
E2eProfileType_t profile_type;
uint16_t data_id;
uint8_t data_length;
uint8_t counter_offset;
uint8_t crc_offset;
uint8_t timeout_ms;
uint32_t max_delta_counter;
} E2eConfig_t;
/* E2E State */
typedef struct {
bool initialized;
E2eConfig_t profiles[E2E_MAX_PROFILES];
uint8_t profile_count;
uint8_t counters[E2E_MAX_PROFILES];
uint32_t last_receive_time[E2E_MAX_PROFILES];
uint32_t error_counters[E2E_MAX_PROFILES];
Mutex_t mutex;
} E2eState_t;
static E2eState_t e2e_state;
/* Initialize E2E Protection */
KernelStatus_t e2e_protection_init(void) {
if (e2e_state.initialized) {
return KERNEL_ERROR;
}
memset(&e2e_state, 0, sizeof(E2eState_t));
mutex_create(&e2e_state.mutex, false);
e2e_state.initialized = true;
return KERNEL_OK;
}
/* Register E2E Profile */
KernelStatus_t e2e_register_profile(const E2eConfig_t* config) {
if (!e2e_state.initialized || config == NULL) {
return KERNEL_ERROR;
}
if (e2e_state.profile_count >= E2E_MAX_PROFILES) {
return KERNEL_OUT_OF_MEMORY;
}
mutex_lock(&e2e_state.mutex, 100);
e2e_state.profiles[e2e_state.profile_count] = *config;
e2e_state.counters[e2e_state.profile_count] = 0;
e2e_state.last_receive_time[e2e_state.profile_count] = 0;
e2e_state.error_counters[e2e_state.profile_count] = 0;
e2e_state.profile_count++;
mutex_unlock(&e2e_state.mutex);
return KERNEL_OK;
}
/* Protect Message (Add E2E header) */
KernelStatus_t e2e_protect_message(uint8_t profile_id, CanMessage_t* message) {
if (!e2e_state.initialized || message == NULL) {
return KERNEL_ERROR;
}
if (profile_id >= e2e_state.profile_count) {
return KERNEL_INVALID_PARAMETER;
}
mutex_lock(&e2e_state.mutex, 100);
E2eConfig_t* config = &e2e_state.profiles[profile_id];
/* Add counter */
message->data[config->counter_offset] = e2e_state.counters[profile_id];
/* Calculate CRC */
uint8_t crc = e2e_calculate_crc8(message->data, config->data_length);
/* Add CRC */
message->data[config->crc_offset] = crc;
/* Increment counter */
e2e_state.counters[profile_id]++;
mutex_unlock(&e2e_state.mutex);
return KERNEL_OK;
}
/* Check Message (Verify E2E header) */
KernelStatus_t e2e_check_message(uint8_t profile_id, const CanMessage_t* message,
bool* is_valid) {
if (!e2e_state.initialized || message == NULL || is_valid == NULL) {
return KERNEL_ERROR;
}
if (profile_id >= e2e_state.profile_count) {
return KERNEL_INVALID_PARAMETER;
}
mutex_lock(&e2e_state.mutex, 100);
E2eConfig_t* config = &e2e_state.profiles[profile_id];
*is_valid = false;
/* Check counter */
uint8_t received_counter = message->data[config->counter_offset];
uint8_t expected_counter = e2e_state.counters[profile_id];
uint32_t delta = (received_counter - expected_counter) & 0xFF;
if (delta > config->max_delta_counter) {
/* Counter error */
e2e_state.error_counters[profile_id]++;
mutex_unlock(&e2e_state.mutex);
return KERNEL_ERROR;
}
/* Check CRC */
uint8_t calculated_crc = e2e_calculate_crc8(message->data,
config->data_length);
uint8_t received_crc = message->data[config->crc_offset];
if (calculated_crc != received_crc) {
/* CRC error */
e2e_state.error_counters[profile_id]++;
mutex_unlock(&e2e_state.mutex);
return KERNEL_ERROR;
}
/* Update state */
e2e_state.counters[profile_id] = received_counter;
e2e_state.last_receive_time[profile_id] = kernel_get_tick_count();
*is_valid = true;
mutex_unlock(&e2e_state.mutex);
return KERNEL_OK;
}
/* Calculate CRC-8 */
static uint8_t e2e_calculate_crc8(const uint8_t* data, uint8_t length) {
uint8_t crc = 0xFF; /* Initial value */
for (uint8_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80) {
crc = (crc << 1) ^ E2E_CRC_POLYNOMIAL;
} else {
crc <<= 1;
}
}
}
return crc;
}
/* Calculate CRC-16 */
static uint16_t e2e_calculate_crc16(const uint8_t* data, uint8_t length) {
uint16_t crc = 0xFFFF;
for (uint8_t i = 0; i < length; i++) {
crc ^= (data[i] << 8);
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ 0x1021;
} else {
crc <<= 1;
}
}
}
return crc;
}
/* Calculate CRC-32 */
static uint32_t e2e_calculate_crc32(const uint8_t* data, uint8_t length) {
uint32_t crc = 0xFFFFFFFF;
for (uint8_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 1) {
crc = (crc >> 1) ^ 0xEDB88320;
} else {
crc >>= 1;
}
}
}
return ~crc;
}
/* Get E2E Error Counter */
uint32_t e2e_get_error_count(uint8_t profile_id) {
if (profile_id >= e2e_state.profile_count) {
return 0;
}
return e2e_state.error_counters[profile_id];
}
/* Reset E2E State */
KernelStatus_t e2e_reset(uint8_t profile_id) {
if (!e2e_state.initialized) {
return KERNEL_ERROR;
}
if (profile_id >= e2e_state.profile_count) {
return KERNEL_INVALID_PARAMETER;
}
mutex_lock(&e2e_state.mutex, 100);
e2e_state.counters[profile_id] = 0;
e2e_state.last_receive_time[profile_id] = 0;
e2e_state.error_counters[profile_id] = 0;
mutex_unlock(&e2e_state.mutex);
return KERNEL_OK;
}
/* E2E Main Function */
void e2e_protection_main_function(void) {
if (!e2e_state.initialized) {
return;
}
uint32_t current_time = kernel_get_tick_count();
mutex_lock(&e2e_state.mutex, 100);
/* Check timeouts */
for (uint8_t i = 0; i < e2e_state.profile_count; i++) {
E2eConfig_t* config = &e2e_state.profiles[i];
if (e2e_state.last_receive_time[i] > 0) {
if ((current_time - e2e_state.last_receive_time[i]) >
config->timeout_ms) {
/* Timeout error */
e2e_state.error_counters[i]++;
e2e_state.last_receive_time[i] = 0;
}
}
}
mutex_unlock(&e2e_state.mutex);
}