Safe Communication Framework 0.1.0 build feea4f9
ERTMS/ETCS safe communication (Subset-037 EuroRadio, Subset-098 RBC/RBC), CENELEC EN 50128 SIL 4 oriented
Loading...
Searching...
No Matches
saf.h File Reference

Safety Functional (SaF) sub-layer — shared by Subset-037 and Subset-098 (ERTMS/ETCS Subset-037 §7). More...

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "safecomm/status.h"
#include "safecomm/mac/mac.h"
#include "safecomm/transport/transport.h"
Include dependency graph for saf.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  safecomm_saf_config_t
 Static configuration for one SaF connection. More...
struct  safecomm_saf_conn_t
 SaF connection object. Caller-allocated, zero-initialised, opaque in practice — fields are not part of the API contract. More...
struct  safecomm_session_vital_state_t
 Vital session state for 2oo2 hot redundancy and active/warm-standby failover. More...

Macros

#define SAFECOMM_SAF_MAX_PDU   1024U
 Largest SaF user-data PDU this build accepts (bytes).
#define SAFECOMM_SAF_AU1_LEN   13U
 Authentication-phase frame lengths (Subset-037-2 §6.2.5), bytes.
#define SAFECOMM_SAF_AU2_LEN   21U
#define SAFECOMM_SAF_AU3_LEN   9U
#define SAFECOMM_SAF_AR_LEN   9U
#define SAFECOMM_SAF_DATA_OVERHEAD   13U
 Sa-DATA framing overhead around the user PDU: header(1) + sequence(4) + MAC(8).
#define SAFECOMM_SAF_DI_LEN   3U
 Sa-DISCONNECT frame length (header + reason + sub-reason).

Enumerations

enum  safecomm_saf_frame_kind_t {
  SAFECOMM_SAF_FRAME_UNKNOWN = 0 , SAFECOMM_SAF_FRAME_AU1 , SAFECOMM_SAF_FRAME_AU2 , SAFECOMM_SAF_FRAME_AU3 ,
  SAFECOMM_SAF_FRAME_DATA , SAFECOMM_SAF_FRAME_DISCONNECT , SAFECOMM_SAF_FRAME_AR
}
 Frame kind by its header MTI, for a caller that routes received frames itself. More...
enum  safecomm_saf_role_t { SAFECOMM_SAF_ROLE_INITIATOR = 0 , SAFECOMM_SAF_ROLE_RESPONDER }
 SaF connection role. More...
enum  safecomm_saf_state_t {
  SAFECOMM_SAF_STATE_IDLE = 0 , SAFECOMM_SAF_STATE_WAIT_AU2 , SAFECOMM_SAF_STATE_WAIT_AU3 , SAFECOMM_SAF_STATE_DATA ,
  SAFECOMM_SAF_STATE_DISCONNECTING
}
 SaF state-machine state (observable, for logging / tests). More...

Functions

safecomm_status_t safecomm_saf_init (safecomm_saf_conn_t *conn, const safecomm_saf_config_t *cfg, const safecomm_transport_t *transport)
 Initialise a SaF connection object (no I/O yet).
safecomm_status_t safecomm_saf_connect (safecomm_saf_conn_t *conn)
 Run the AU1/AU2/AU3 handshake to completion (blocking).
safecomm_status_t safecomm_saf_send (safecomm_saf_conn_t *conn, const uint8_t *pdu, size_t pdu_len)
 Send one user PDU as a MAC-protected, sequence-numbered Sa-DATA.
safecomm_status_t safecomm_saf_recv (safecomm_saf_conn_t *conn, uint8_t *out, size_t out_cap, size_t *out_len)
 Receive and verify one Sa-DATA PDU (blocking).
safecomm_saf_frame_kind_t safecomm_saf_frame_kind (const uint8_t *frame, size_t frame_len)
 Classify a received frame by its header MTI (no MAC check).
safecomm_status_t safecomm_saf_au1_fields (const uint8_t *au1, size_t au1_len, uint32_t *out_peer_id, uint8_t out_ra[SAFECOMM_MAC_RAND_LEN])
 Read the caller's ETCS identity and initiator random RA out of an AU1 frame (no MAC exists on AU1). A responder that serves many peers uses the identity to pick the peer's KMAC and configure the connection, and RA to pair a shared RB with the handshake it belongs to.
safecomm_status_t safecomm_saf_responder_on_au1 (safecomm_saf_conn_t *conn, const uint8_t *au1, size_t au1_len, const uint8_t rb[SAFECOMM_MAC_RAND_LEN], uint8_t *out_au2, size_t out_cap, size_t *out_len)
 Responder: accept AU1, derive the session key from RA and the caller's rb, and build AU2.
safecomm_status_t safecomm_saf_responder_on_au3 (safecomm_saf_conn_t *conn, const uint8_t *au3, size_t au3_len, uint8_t *out_ar, size_t out_cap, size_t *out_len)
 Responder: verify AU3 and build the AR confirmation; the connection enters DATA.
safecomm_status_t safecomm_saf_accept_frame (safecomm_saf_conn_t *conn, const uint8_t *frame, size_t frame_len, uint8_t *out, size_t out_cap, size_t *out_len)
 Verify one received Sa-DATA or Sa-DISCONNECT frame (the checks of safecomm_saf_recv(), without the transport).
safecomm_status_t safecomm_saf_frame_sent (safecomm_saf_conn_t *conn)
 Record that the caller transmitted the frame from safecomm_saf_prepare_send() itself: advances the send sequence exactly as safecomm_saf_commit_send() does after a successful transport send.
safecomm_status_t safecomm_saf_disconnect_frame (safecomm_saf_role_t role, uint8_t *out, size_t out_cap, size_t *out_len)
 Build a Sa-DISCONNECT (reason 0, sub-reason 0) for a side of the given role, without any connection state - e.g. a responder releasing a Sa-DATA frame that belongs to no connection it holds (the peer's session is stale, typically after this node restarted), so the peer reconnects at once instead of waiting out its supervision time. Unauthenticated, as every Sa-DISCONNECT (Subset-037-2 §6.2.3.3.3.2).
void safecomm_saf_set_time (safecomm_saf_conn_t *conn, uint32_t now_ms)
 Orderly Sa-DISCONNECT, then return the object to IDLE.
safecomm_status_t safecomm_saf_supervise (safecomm_saf_conn_t *conn)
 Idle-link supervision (EN 50159 delay and loss): in DATA, if no valid frame arrived for cfg.t_supervision_ms the connection goes to IDLE and SAFECOMM_STATUS_TIMEOUT is returned. Call it cyclically. The first call arms the timer. t_supervision_ms == 0 disables it.
safecomm_status_t safecomm_saf_disconnect (safecomm_saf_conn_t *conn)
safecomm_saf_state_t safecomm_saf_state (const safecomm_saf_conn_t *conn)
 Current state (for logging / tests). Returns IDLE for NULL.
safecomm_status_t safecomm_saf_export_session_state (const safecomm_saf_conn_t *conn, safecomm_session_vital_state_t *out_state)
 Export vital session state for warm/hot standby synchronization.
safecomm_status_t safecomm_saf_import_session_state (safecomm_saf_conn_t *conn, const safecomm_session_vital_state_t *in_state)
 Import vital session state upon warm-standby takeover or channel resynchronization.
safecomm_status_t safecomm_saf_prepare_send (safecomm_saf_conn_t *conn, const uint8_t *pdu, size_t pdu_len, uint8_t *out_frame, size_t out_frame_cap, size_t *out_frame_len)
 Prepare and MAC-protect one Sa-DATA frame without transmitting it (for 2oo2 cross-checking).
safecomm_status_t safecomm_saf_commit_send (safecomm_saf_conn_t *conn, const uint8_t *frame, size_t frame_len)
 Transmit an already prepared and cross-compared Sa-DATA frame.

Detailed Description

Safety Functional (SaF) sub-layer — shared by Subset-037 and Subset-098 (ERTMS/ETCS Subset-037 §7).

The SaF sub-layer provides an authenticated, sequence-checked, supervised message channel over an unreliable safecomm_transport_t:

Sa-CONNECT establish + AU1/AU2/AU3 mutual authentication Sa-DATA send / receive a MAC-protected, sequence-numbered PDU Sa-DISCONNECT orderly teardown

State machine (Subset-037 §7.4): IDLE -> WAIT_AU2 -> WAIT_AU3 -> DATA -> DISCONNECTING -> IDLE with any state transitioning to IDLE on a supervision timeout or a transport / authentication failure.

REQ-SC-SAF-001..030 — see docs/requirements/SRS.md.

Definition in file saf.h.

Macro Definition Documentation

◆ SAFECOMM_SAF_MAX_PDU

#define SAFECOMM_SAF_MAX_PDU   1024U

Largest SaF user-data PDU this build accepts (bytes).

Definition at line 36 of file saf.h.

◆ SAFECOMM_SAF_AU1_LEN

#define SAFECOMM_SAF_AU1_LEN   13U

Authentication-phase frame lengths (Subset-037-2 §6.2.5), bytes.

Definition at line 39 of file saf.h.

◆ SAFECOMM_SAF_AU2_LEN

#define SAFECOMM_SAF_AU2_LEN   21U

Definition at line 40 of file saf.h.

◆ SAFECOMM_SAF_AU3_LEN

#define SAFECOMM_SAF_AU3_LEN   9U

Definition at line 41 of file saf.h.

◆ SAFECOMM_SAF_AR_LEN

#define SAFECOMM_SAF_AR_LEN   9U

Definition at line 42 of file saf.h.

◆ SAFECOMM_SAF_DATA_OVERHEAD

#define SAFECOMM_SAF_DATA_OVERHEAD   13U

Sa-DATA framing overhead around the user PDU: header(1) + sequence(4) + MAC(8).

Definition at line 44 of file saf.h.

◆ SAFECOMM_SAF_DI_LEN

#define SAFECOMM_SAF_DI_LEN   3U

Sa-DISCONNECT frame length (header + reason + sub-reason).

Definition at line 240 of file saf.h.

Enumeration Type Documentation

◆ safecomm_saf_frame_kind_t

Frame kind by its header MTI, for a caller that routes received frames itself.

Definition at line 47 of file saf.h.

◆ safecomm_saf_role_t

SaF connection role.

Enumerator
SAFECOMM_SAF_ROLE_INITIATOR 

Sends AU1, i.e. the calling peer / EVC / handover-giving RBC.

SAFECOMM_SAF_ROLE_RESPONDER 

Answers with AU2.

Definition at line 59 of file saf.h.

◆ safecomm_saf_state_t

SaF state-machine state (observable, for logging / tests).

Definition at line 66 of file saf.h.

Function Documentation

◆ safecomm_saf_init()

safecomm_status_t safecomm_saf_init ( safecomm_saf_conn_t * conn,
const safecomm_saf_config_t * cfg,
const safecomm_transport_t * transport )

Initialise a SaF connection object (no I/O yet).

Parameters
conncaller-allocated, will be fully overwritten. Non-NULL.
cfgstatic configuration, copied. Non-NULL.
transportfully-populated transport, copied. Non-NULL, .send/.recv non-NULL.
Returns
SAFECOMM_STATUS_OK / _INVALID_PARAM / _NOT_IMPLEMENTED.
Note
REQ-SC-SAF-002.

Definition at line 125 of file saf.c.

◆ safecomm_saf_connect()

safecomm_status_t safecomm_saf_connect ( safecomm_saf_conn_t * conn)

Run the AU1/AU2/AU3 handshake to completion (blocking).

Parameters
connan initialised, IDLE connection. Non-NULL.
Returns
SAFECOMM_STATUS_OK (now in DATA), _AUTH_FAILED, _TIMEOUT, _TRANSPORT, _STATE, or _NOT_IMPLEMENTED.
Note
REQ-SC-SAF-010. When cfg.t_connect_ms is non-zero the whole handshake must finish within it on the clock supplied through safecomm_saf_set_time() (the transport must keep that clock current while it blocks); otherwise the result is _TIMEOUT and the connection returns to IDLE (REQ-SC-SAF-022).

Definition at line 241 of file saf.c.

◆ safecomm_saf_send()

safecomm_status_t safecomm_saf_send ( safecomm_saf_conn_t * conn,
const uint8_t * pdu,
size_t pdu_len )

Send one user PDU as a MAC-protected, sequence-numbered Sa-DATA.

Parameters
conna connection in DATA. Non-NULL.
pduuser bytes. Non-NULL when pdu_len > 0.
pdu_len1..SAFECOMM_SAF_MAX_PDU.
Returns
SAFECOMM_STATUS_OK / _STATE / _INVALID_PARAM / _TRANSPORT / _BUFFER_TOO_SMALL / _NOT_IMPLEMENTED.
Note
REQ-SC-SAF-015.

Definition at line 643 of file saf.c.

◆ safecomm_saf_recv()

safecomm_status_t safecomm_saf_recv ( safecomm_saf_conn_t * conn,
uint8_t * out,
size_t out_cap,
size_t * out_len )

Receive and verify one Sa-DATA PDU (blocking).

Parameters
conna connection in DATA. Non-NULL.
outdestination for the user bytes. Non-NULL.
out_capcapacity of out.
out_lenreceives the user-byte count. Non-NULL.
Returns
SAFECOMM_STATUS_OK, _MAC_MISMATCH, _SEQ_ERROR, _TIMEOUT, _PEER_DISCONNECT, _BUFFER_TOO_SMALL, _STATE, or _NOT_IMPLEMENTED.
Note
REQ-SC-SAF-018. A MAC or sequence failure drops the connection to IDLE. Any correctly-shaped Sa-DISCONNECT (right length and message type) is acted on (_PEER_DISCONNECT, IDLE) with no further check: Subset-037-2 §6.2.3.3.3.2 does not require release-phase authentication, since a forged one can only end the connection early (an availability effect), never inject or alter safety data (REQ-SC-SAF-023).

Definition at line 657 of file saf.c.

◆ safecomm_saf_frame_kind()

safecomm_saf_frame_kind_t safecomm_saf_frame_kind ( const uint8_t * frame,
size_t frame_len )

Classify a received frame by its header MTI (no MAC check).

Returns
the frame kind; SAFECOMM_SAF_FRAME_UNKNOWN for NULL, empty or an unknown MTI.
Note
REQ-SC-SAF-040.

Definition at line 454 of file saf.c.

◆ safecomm_saf_au1_fields()

safecomm_status_t safecomm_saf_au1_fields ( const uint8_t * au1,
size_t au1_len,
uint32_t * out_peer_id,
uint8_t out_ra[SAFECOMM_MAC_RAND_LEN] )

Read the caller's ETCS identity and initiator random RA out of an AU1 frame (no MAC exists on AU1). A responder that serves many peers uses the identity to pick the peer's KMAC and configure the connection, and RA to pair a shared RB with the handshake it belongs to.

Parameters
au1the received frame. Non-NULL.
au1_lenits length; must be SAFECOMM_SAF_AU1_LEN.
out_peer_idreceives the 24-bit source ETCS identity. Non-NULL.
out_rareceives SAFECOMM_MAC_RAND_LEN bytes. Non-NULL.
Returns
SAFECOMM_STATUS_OK / _INVALID_PARAM / _AUTH_FAILED (not a well-formed AU1).
Note
REQ-SC-SAF-041.

Definition at line 474 of file saf.c.

◆ safecomm_saf_responder_on_au1()

safecomm_status_t safecomm_saf_responder_on_au1 ( safecomm_saf_conn_t * conn,
const uint8_t * au1,
size_t au1_len,
const uint8_t rb[SAFECOMM_MAC_RAND_LEN],
uint8_t * out_au2,
size_t out_cap,
size_t * out_len )

Responder: accept AU1, derive the session key from RA and the caller's rb, and build AU2.

Parameters
connan initialised RESPONDER connection, in any state (a new AU1 restarts the connection). Non-NULL.
au1the received AU1. Non-NULL.
au1_lenits length.
rbthe responder random, SAFECOMM_MAC_RAND_LEN bytes from a secure source. Non-NULL.
out_au2receives AU2 to transmit. Non-NULL.
out_capcapacity of out_au2, >= SAFECOMM_SAF_AU2_LEN.
out_lenreceives SAFECOMM_SAF_AU2_LEN. Non-NULL.
Returns
SAFECOMM_STATUS_OK (now WAIT_AU3; the connect budget starts at the current now_ms), _AUTH_FAILED (malformed AU1 or unexpected peer identity; now IDLE), _STATE (not a responder), _BUFFER_TOO_SMALL, _INVALID_PARAM.
Note
REQ-SC-SAF-042.

Definition at line 490 of file saf.c.

◆ safecomm_saf_responder_on_au3()

safecomm_status_t safecomm_saf_responder_on_au3 ( safecomm_saf_conn_t * conn,
const uint8_t * au3,
size_t au3_len,
uint8_t * out_ar,
size_t out_cap,
size_t * out_len )

Responder: verify AU3 and build the AR confirmation; the connection enters DATA.

Parameters
conna RESPONDER connection in WAIT_AU3. Non-NULL.
au3the received AU3. Non-NULL.
au3_lenits length.
out_arreceives AR to transmit. Non-NULL.
out_capcapacity of out_ar, >= SAFECOMM_SAF_AR_LEN.
out_lenreceives SAFECOMM_SAF_AR_LEN. Non-NULL.
Returns
SAFECOMM_STATUS_OK (now DATA), _AUTH_FAILED (bad AU3 or MAC; now IDLE), _TIMEOUT (cfg.t_connect_ms elapsed since AU1 on the safecomm_saf_set_time() clock; now IDLE), _STATE, _BUFFER_TOO_SMALL, _INVALID_PARAM.
Note
REQ-SC-SAF-043.

Definition at line 519 of file saf.c.

◆ safecomm_saf_accept_frame()

safecomm_status_t safecomm_saf_accept_frame ( safecomm_saf_conn_t * conn,
const uint8_t * frame,
size_t frame_len,
uint8_t * out,
size_t out_cap,
size_t * out_len )

Verify one received Sa-DATA or Sa-DISCONNECT frame (the checks of safecomm_saf_recv(), without the transport).

Returns
as safecomm_saf_recv().
Note
REQ-SC-SAF-044.

Definition at line 680 of file saf.c.

◆ safecomm_saf_frame_sent()

safecomm_status_t safecomm_saf_frame_sent ( safecomm_saf_conn_t * conn)

Record that the caller transmitted the frame from safecomm_saf_prepare_send() itself: advances the send sequence exactly as safecomm_saf_commit_send() does after a successful transport send.

Returns
SAFECOMM_STATUS_OK / _STATE (not in DATA) / _INVALID_PARAM.
Note
REQ-SC-SAF-045.

Definition at line 549 of file saf.c.

◆ safecomm_saf_disconnect_frame()

safecomm_status_t safecomm_saf_disconnect_frame ( safecomm_saf_role_t role,
uint8_t * out,
size_t out_cap,
size_t * out_len )

Build a Sa-DISCONNECT (reason 0, sub-reason 0) for a side of the given role, without any connection state - e.g. a responder releasing a Sa-DATA frame that belongs to no connection it holds (the peer's session is stale, typically after this node restarted), so the peer reconnects at once instead of waiting out its supervision time. Unauthenticated, as every Sa-DISCONNECT (Subset-037-2 §6.2.3.3.3.2).

Parameters
rolethe sending side's role (sets the direction flag).
outreceives SAFECOMM_SAF_DI_LEN bytes. Non-NULL.
out_capcapacity of out.
out_lenreceives SAFECOMM_SAF_DI_LEN. Non-NULL.
Returns
SAFECOMM_STATUS_OK / _BUFFER_TOO_SMALL / _INVALID_PARAM.
Note
REQ-SC-SAF-046.

Definition at line 563 of file saf.c.

◆ safecomm_saf_set_time()

void safecomm_saf_set_time ( safecomm_saf_conn_t * conn,
uint32_t now_ms )

Orderly Sa-DISCONNECT, then return the object to IDLE.

Parameters
connany non-IDLE connection. Non-NULL.
Returns
SAFECOMM_STATUS_OK / _NOT_IMPLEMENTED. Always ends IDLE.
Note
REQ-SC-SAF-020.

Set the current time for supervision. The library reads no clock (it must not call the OS); the caller passes a monotonic millisecond counter (wrap-around safe) before recv / supervise.

Note
REQ-SC-SAF-020.

Definition at line 761 of file saf.c.

◆ safecomm_saf_supervise()

safecomm_status_t safecomm_saf_supervise ( safecomm_saf_conn_t * conn)

Idle-link supervision (EN 50159 delay and loss): in DATA, if no valid frame arrived for cfg.t_supervision_ms the connection goes to IDLE and SAFECOMM_STATUS_TIMEOUT is returned. Call it cyclically. The first call arms the timer. t_supervision_ms == 0 disables it.

Returns
OK while supervised and alive; TIMEOUT when the link is declared lost; STATE if not in DATA; INVALID_PARAM.
Note
REQ-SC-SAF-021.

Definition at line 769 of file saf.c.

◆ safecomm_saf_disconnect()

safecomm_status_t safecomm_saf_disconnect ( safecomm_saf_conn_t * conn)

Definition at line 799 of file saf.c.

◆ safecomm_saf_state()

safecomm_saf_state_t safecomm_saf_state ( const safecomm_saf_conn_t * conn)

Current state (for logging / tests). Returns IDLE for NULL.

Definition at line 819 of file saf.c.

◆ safecomm_saf_export_session_state()

safecomm_status_t safecomm_saf_export_session_state ( const safecomm_saf_conn_t * conn,
safecomm_session_vital_state_t * out_state )

Export vital session state for warm/hot standby synchronization.

Parameters
connactive connection. Non-NULL.
out_statedestination buffer. Non-NULL.
Returns
SAFECOMM_STATUS_OK / _INVALID_PARAM.

Definition at line 824 of file saf.c.

◆ safecomm_saf_import_session_state()

safecomm_status_t safecomm_saf_import_session_state ( safecomm_saf_conn_t * conn,
const safecomm_session_vital_state_t * in_state )

Import vital session state upon warm-standby takeover or channel resynchronization.

Parameters
conninitialised connection object. Non-NULL.
in_statecheckpointed state. Non-NULL.
Returns
SAFECOMM_STATUS_OK / _INVALID_PARAM.

Definition at line 846 of file saf.c.

◆ safecomm_saf_prepare_send()

safecomm_status_t safecomm_saf_prepare_send ( safecomm_saf_conn_t * conn,
const uint8_t * pdu,
size_t pdu_len,
uint8_t * out_frame,
size_t out_frame_cap,
size_t * out_frame_len )

Prepare and MAC-protect one Sa-DATA frame without transmitting it (for 2oo2 cross-checking).

Parameters
connconnection in DATA. Non-NULL.
pduuser payload bytes. Non-NULL.
pdu_lenpayload length.
out_framereceives the fully formatted on-the-wire frame. Non-NULL.
out_frame_capcapacity of out_frame.
out_frame_lenreceives total length of the frame. Non-NULL.
Returns
SAFECOMM_STATUS_OK / _STATE / _BUFFER_TOO_SMALL / _INVALID_PARAM.

Definition at line 581 of file saf.c.

◆ safecomm_saf_commit_send()

safecomm_status_t safecomm_saf_commit_send ( safecomm_saf_conn_t * conn,
const uint8_t * frame,
size_t frame_len )

Transmit an already prepared and cross-compared Sa-DATA frame.

Parameters
connconnection in DATA. Non-NULL.
frameframe from safecomm_saf_prepare_send(). Non-NULL.
frame_lenframe length.
Returns
SAFECOMM_STATUS_OK / _TRANSPORT / _STATE / _INVALID_PARAM.

Definition at line 623 of file saf.c.