11#include "rte/oal/random/rte_random.h"
12#include "safecomm/euroradio/euroradio.h"
16#define AB_GP_SAF_ETY_RBC 1U
22 uint8_t
kmac[SAFECOMM_MAC_KEY_LEN];
27static safecomm_status_t
no_send(
void *user,
const uint8_t *buf,
size_t len)
32 return SAFECOMM_STATUS_TRANSPORT;
35static safecomm_status_t
no_recv(
void *user, uint8_t *buf,
size_t cap,
size_t *out_len)
41 return SAFECOMM_STATUS_TRANSPORT;
50 if (
s_keys[i].in_use && (
s_keys[i].peer_etcs_id == peer_etcs_id))
68 return &s->
slots[train_id - 1U];
81 uint32_t peer_id = 0U;
82 uint8_t ra[SAFECOMM_MAC_RAND_LEN];
83 safecomm_er_config_t er;
84 safecomm_saf_config_t cfg;
85 const safecomm_transport_t none = {
no_send,
no_recv, NULL, NULL };
89 st = safecomm_saf_au1_fields(au1, SAFECOMM_SAF_AU1_LEN, &peer_id, ra);
90 if (st != SAFECOMM_STATUS_OK)
98 reject(out, SAFECOMM_STATUS_AUTH_FAILED);
101 (void)memset(&er, 0,
sizeof(er));
102 er.side = SAFECOMM_ER_SIDE_RBC;
103 (void)memcpy(er.kmac, key->
kmac,
sizeof(er.kmac));
105 er.etcs_id_peer = peer_id;
106 (void)safecomm_er_make_saf_config(&er, &cfg);
108 (void)safecomm_saf_init(&slot->
conn, &cfg, &none);
109 (void)memset(&cfg, 0,
sizeof(cfg));
110 safecomm_saf_set_time(&slot->
conn, now_ms);
111 st = safecomm_saf_responder_on_au1(&slot->
conn, au1, SAFECOMM_SAF_AU1_LEN, rb, out->
frame,
sizeof(out->
frame),
113 if (st != SAFECOMM_STATUS_OK)
119 out->
status = SAFECOMM_STATUS_OK;
138 if (
s_keys[i].in_use && (
s_keys[i].peer_etcs_id == peer_etcs_id))
156 (void)memcpy(slot->
kmac, kmac,
sizeof(slot->
kmac));
162 if ((c >=
'0') && (c <=
'9'))
166 if ((c >=
'a') && (c <=
'f'))
168 return (c -
'a') + 10;
170 if ((c >=
'A') && (c <=
'F'))
172 return (c -
'A') + 10;
178static bool parse_key_line(
char *line, uint32_t *out_id, uint8_t out_kmac[SAFECOMM_MAC_KEY_LEN])
180 char *id_str = strtok(line,
" \t\r\n");
181 char *hex = strtok(NULL,
" \t\r\n");
182 char *extra = strtok(NULL,
" \t\r\n");
187 if ((id_str == NULL) || (hex == NULL) || (extra != NULL) || (strlen(hex) != (2U * SAFECOMM_MAC_KEY_LEN)))
191 id = strtoul(id_str, &end, 0);
192 if ((end == id_str) || (*end !=
'\0') || (
id > 0xFFFFFFUL))
196 for (i = 0U; i < SAFECOMM_MAC_KEY_LEN; i++)
201 if ((hi < 0) || (lo < 0))
205 out_kmac[i] = (uint8_t)((hi << 4) | lo);
207 *out_id = (uint32_t)
id;
217 if ((path == NULL) || (out_count == NULL))
222 fp = fopen(path,
"r");
227 while (ok && (fgets(line, (
int)
sizeof(line), fp) != NULL))
229 char *hash = strchr(line,
'#');
232 uint8_t kmac[SAFECOMM_MAC_KEY_LEN];
238 while ((*p ==
' ') || (*p ==
'\t') || (*p ==
'\r') || (*p ==
'\n'))
247 (void)memset(kmac, 0,
sizeof(kmac));
253 (void)memset(line, 0,
sizeof(line));
264 (void)memset(s, 0,
sizeof(*s));
274 safecomm_status_t st;
280 (void)memset(out, 0,
sizeof(*out));
282 if ((slot == NULL) || (frame == NULL) || (frame_len == 0U))
284 reject(out, SAFECOMM_STATUS_INVALID_PARAM);
287 safecomm_saf_set_time(&slot->
conn, now_ms);
289 switch (safecomm_saf_frame_kind(frame, frame_len))
291 case SAFECOMM_SAF_FRAME_AU1:
293 uint32_t peer_id = 0U;
294 uint8_t ra[SAFECOMM_MAC_RAND_LEN];
296 st = safecomm_saf_au1_fields(frame, frame_len, &peer_id, ra);
297 if (st != SAFECOMM_STATUS_OK)
304 uint8_t rb[SAFECOMM_MAC_RAND_LEN];
306 if (rte_random_fill(rb,
sizeof(rb)) != RTE_STATUS_OK)
308 reject(out, SAFECOMM_STATUS_NOT_INITIALISED);
316 (void)memcpy(&out->
rb_share[1], ra, SAFECOMM_MAC_RAND_LEN);
317 (void)memcpy(&out->
rb_share[1U + SAFECOMM_MAC_RAND_LEN], rb, SAFECOMM_MAC_RAND_LEN);
319 (void)memset(rb, 0,
sizeof(rb));
322 if (slot->
rb_parked && (memcmp(slot->
rb_ra, ra,
sizeof(ra)) == 0))
328 (void)memcpy(slot->
au1, frame, SAFECOMM_SAF_AU1_LEN);
333 case SAFECOMM_SAF_FRAME_AU3:
334 st = safecomm_saf_responder_on_au3(&slot->
conn, frame, frame_len, out->
frame,
sizeof(out->
frame),
336 if (st != SAFECOMM_STATUS_OK)
343 case SAFECOMM_SAF_FRAME_DATA:
344 case SAFECOMM_SAF_FRAME_DISCONNECT:
345 st = safecomm_saf_accept_frame(&slot->
conn, frame, frame_len, out->
app,
sizeof(out->
app), &out->
app_len);
346 if (st == SAFECOMM_STATUS_OK)
350 else if (st == SAFECOMM_STATUS_PEER_DISCONNECT)
354 else if ((st == SAFECOMM_STATUS_STATE) && (safecomm_saf_state(&slot->
conn) == SAFECOMM_SAF_STATE_IDLE) &&
355 (safecomm_saf_frame_kind(frame, frame_len) == SAFECOMM_SAF_FRAME_DATA) &&
356 (safecomm_saf_disconnect_frame(SAFECOMM_SAF_ROLE_RESPONDER, out->
frame,
sizeof(out->
frame),
372 reject(out, SAFECOMM_STATUS_STATE);
388 (void)memset(out, 0,
sizeof(*out));
391 reject(out, SAFECOMM_STATUS_INVALID_PARAM);
397 reject(out, SAFECOMM_STATUS_INVALID_PARAM);
401 rb = &payload[1U + SAFECOMM_MAC_RAND_LEN];
402 if (slot->
au1_parked && (memcmp(&slot->
au1[5], ra, SAFECOMM_MAC_RAND_LEN) == 0))
408 (void)memcpy(slot->
rb_ra, ra, SAFECOMM_MAC_RAND_LEN);
409 (void)memcpy(slot->
rb, rb, SAFECOMM_MAC_RAND_LEN);
415 uint8_t *out_frame,
size_t out_cap,
size_t *out_len)
419 if ((slot == NULL) || (pdu == NULL) || (pdu_len > (
size_t)
AB_GP_SAF_PDU_MAX) || (out_frame == NULL) ||
424 if (safecomm_saf_prepare_send(&slot->
conn, pdu, pdu_len, out_frame, out_cap, out_len) != SAFECOMM_STATUS_OK)
428 return safecomm_saf_frame_sent(&slot->
conn) == SAFECOMM_STATUS_OK;
436 if ((s == NULL) || !s->
enabled)
442 safecomm_saf_conn_t *conn = &s->
slots[i].
conn;
444 if (safecomm_saf_state(conn) == SAFECOMM_SAF_STATE_DATA)
446 safecomm_saf_set_time(conn, now_ms);
447 if (safecomm_saf_supervise(conn) == SAFECOMM_STATUS_TIMEOUT)
449 lost |= (uint32_t)1U << i;
463 return safecomm_saf_state(&s->
slots[train_id - 1U].
conn) == SAFECOMM_SAF_STATE_DATA;
469 if ((frame == NULL) || (out == NULL) || (frame_len == 0U) || (frame_len > (
size_t)
AB_GP_SAF_FRAME_MAX))
476 out[2] = (uint8_t)((frame_len >> 8U) & 0xFFU);
477 out[3] = (uint8_t)(frame_len & 0xFFU);
483 const uint8_t **out_frame,
size_t *out_len)
487 if ((env == NULL) || (out_train_id == NULL) || (out_frame == NULL) || (out_len == NULL) ||
492 len = ((size_t)env[2] << 8U) | (
size_t)env[3];
498 *out_train_id = env[1];
static const saf_key_t * key_lookup(uint32_t peer_etcs_id)
bool ab_gp_saf_envelope_decode(const uint8_t env[RBC_TRAIN_ENVELOPE_WIRE_SIZE], uint8_t *out_train_id, const uint8_t **out_frame, size_t *out_len)
Splits a received RBC_MSG_SAF_ENVELOPE relay frame.
void ab_gp_saf_keys_clear(void)
Empties the KMAC table (process-global, shared by every slot).
static saf_key_t s_keys[AB_GP_SAF_KEYS_MAX]
void ab_gp_saf_train_on_peer_rb(ab_gp_saf_train_t *s, const uint8_t *payload, size_t size, uint32_t now_ms, ab_gp_saf_result_t *out)
B only: processes A's PEER_MSG_KIND_SAF_RB payload; answers the parked AU1 when its RA matches.
static int hex_nibble(char c)
static bool parse_key_line(char *line, uint32_t *out_id, uint8_t out_kmac[SAFECOMM_MAC_KEY_LEN])
static void respond_au1(ab_gp_saf_train_t *s, ab_gp_saf_train_slot_t *slot, const uint8_t *au1, const uint8_t *rb, uint32_t now_ms, ab_gp_saf_result_t *out)
bool ab_gp_saf_envelope_encode(uint8_t train_id, const uint8_t *frame, size_t frame_len, uint8_t out[RBC_TRAIN_ENVELOPE_WIRE_SIZE])
Builds an RBC_MSG_SAF_ENVELOPE relay frame (RBC_TRAIN_ENVELOPE_WIRE_SIZE bytes).
bool ab_gp_saf_train_is_connected(const ab_gp_saf_train_t *s, uint8_t train_id)
True if train slot train_id has a connection in DATA.
bool ab_gp_saf_train_wrap(ab_gp_saf_train_t *s, uint8_t train_id, const uint8_t *pdu, size_t pdu_len, uint8_t *out_frame, size_t out_cap, size_t *out_len)
Protects one outbound application PDU for train slot train_id (only in DATA).
static void reject(ab_gp_saf_result_t *out, safecomm_status_t status)
static safecomm_status_t no_recv(void *user, uint8_t *buf, size_t cap, size_t *out_len)
uint32_t ab_gp_saf_train_supervise(ab_gp_saf_train_t *s, uint32_t now_ms)
Idle-link supervision of every connection in DATA (REQ-SC-004).
void ab_gp_saf_train_on_frame(ab_gp_saf_train_t *s, uint8_t train_id, const uint8_t *frame, size_t frame_len, uint32_t now_ms, ab_gp_saf_result_t *out)
Processes one SaF frame received from train slot train_id (1..RTE_EXAMPLE_MAX_TRAINS).
#define AB_GP_SAF_ETY_RBC
bool ab_gp_saf_keys_load_file(const char *path, uint32_t *out_count)
Loads KMACs from a text file: one "<etcs_id> <48 hex chars>" per line (decimal or 0x identity),...
static safecomm_status_t no_send(void *user, const uint8_t *buf, size_t len)
bool ab_gp_saf_keys_install(uint32_t peer_etcs_id, const uint8_t kmac[SAFECOMM_MAC_KEY_LEN])
Installs (or replaces) the KMAC for one train ETCS identity.
static ab_gp_saf_train_slot_t * slot_of(ab_gp_saf_train_t *s, uint8_t train_id)
void ab_gp_saf_train_init(ab_gp_saf_train_t *s, bool enabled, bool is_role_a, uint32_t rbc_etcs_id)
Resets s. enabled false makes every other call a no-op / rejection.
Train link safe communication (Subset-037 SaF) terminated inside A and B - REQ-SC-001,...
#define AB_GP_SAF_FRAME_MAX
Largest SaF frame one Train relay envelope carries.
#define AB_GP_SAF_ENVELOPE_HEADER
Envelope prefix: kind, train_id, 2-byte frame length.
#define AB_GP_SAF_KEYS_MAX
Capacity of the KMAC table (one entry per train ETCS identity).
#define AB_GP_SAF_PDU_MAX
Largest application PDU (ERTMS codec bytes) one protected frame carries.
@ AB_GP_SAF_ACTION_REJECTED
@ AB_GP_SAF_ACTION_DISCONNECTED
#define AB_GP_SAF_PEER_RB_SIZE
PEER_MSG_KIND_SAF_RB payload: train_id(1) + RA(8) + RB(8).
#define RBC_TRAIN_ENVELOPE_WIRE_SIZE
#define RTE_EXAMPLE_MAX_TRAINS
The RBC Train/IL/CTC scenario's shared wire envelope (ADR-029) - one fixed-size struct/frame reused f...
Output of ab_gp_saf_train_on_frame() / _on_peer_rb().
uint8_t app[AB_GP_SAF_PDU_MAX]
uint8_t frame[SAFECOMM_SAF_AU2_LEN]
uint8_t rb_share[AB_GP_SAF_PEER_RB_SIZE]
ab_gp_saf_action_t action
uint8_t rb_ra[SAFECOMM_MAC_RAND_LEN]
uint8_t au1[SAFECOMM_SAF_AU1_LEN]
uint8_t rb[SAFECOMM_MAC_RAND_LEN]
One channel's train-link SaF termination.
ab_gp_saf_train_slot_t slots[RTE_EXAMPLE_MAX_TRAINS]
uint8_t kmac[SAFECOMM_MAC_KEY_LEN]