RBC_Template 0.1.0 build 5fb9afb
Workspace master specification — safety-related railway software around an ERTMS Radio Block Centre (RBC), CENELEC EN 50128 / SIL 4
Loading...
Searching...
No Matches
Safe communication for the RBC: train link (SS-037) and IL link (SS-098)

Status (2026-09-28): train link terminated in A/B, off by default - plan step 3's first increment, started on direct request ahead of steps 1 and 2. With RTE_SAFECOMM_TRAIN_RBC_ID set, RBC_GP's A and B each terminate one Subset-037 SaF responder connection per train (com/ab_gp_saf_train.c), the gateway relays RBC_MSG_SAF_ENVELOPE frames untouched, and the KMAC comes in memory from the KM114 client. Unset (the default, and what every test environment runs today) the train link still carries plain rbc_envelope/ERTMS frames, so SC-02 claim C2.3 and SC-03 claim C3.3 still describe the running system. The IL link is untouched (step 4). See RBC_GP's CLAUDE.md for the design and its verification.

Requirement

ID Requirement
REQ-SC-001 The RBC (GP and GA, vital roles A and B) communicates with the train over a Subset-037 (EuroRadio) safe communication link provided by Platform_Protocol_SafeComm.
REQ-SC-002 The RBC communicates with the interlocking (IL) over a safe communication link that uses the Subset-098 profile of Platform_Protocol_SafeComm (SaF sub-layer over fixed IP).
REQ-SC-003 The vital side terminates the safety layer: it verifies the message authentication code, the sequence numbers and the supervision timers itself. The role C gateways and the RBC_Test_CommServer stay non-vital carriers of protected frames and are never trusted.
REQ-SC-004 A frame that fails the safety check is dropped and reported to the platform; a link whose supervision times out is declared lost, and the application reacts as it does today to a lost link. It never yields an application message.
REQ-SC-005 Keys (pre-shared KMAC) and peer identities come from the specific application (SC-06); no key is compiled into GP or GA.

Open question to confirm: Subset-098 is titled "RBC/RBC Safe Communication Interface" and the library's rbc_rbc profile is written for RBC-to-RBC handover. Using it for the IL means an IL profile (identities, timers, message-set binding) on the same SaF sub-layer, not the handover message set. Confirm the profile parameters with the interlocking supplier's interface specification.

Target architecture

flowchart LR
    TRAIN["Train (EVC)"] -->|SaF/SS-037| CS["RBC_Test_CommServer<br/>(ALE, non-vital carrier)"]
    CS -->|protected frames| GWT["role C gateway (train)"]
    GWT -->|relay| AB1["A/B"]

    IL["IL"] -->|SaF/SS-098| GWIL["role C gateway (il)"]
    GWIL -->|relay| AB2["A/B"]

    AB1 & AB2 -->|"safecomm::safety verifies MAC + sequence + timers"| APP["rbc_envelope (application data) → GP / GA"]
  • Termination. The safety layer ends in the vital processes A and B, one instance per link and per channel. Each channel verifies independently; the 2oo2 cross-comparison then compares the decoded application data, as it does today. The outgoing MAC'd frame is cross-checked (ADR-003 section 7, split-send).
  • Gateways. The role C train, IL, CTC and status gateways keep relaying bytes. They forward protected frames unchanged (a frame is larger than an envelope) and never inspect the payload. Done: the train gateway's relay (gateway_c_train_handler.c) now forwards the true received length instead of always a fixed RBC_TRAIN_ENVELOPE_WIRE_SIZE width (rte_channel_service_read_ex(), Platform_RTE), a prerequisite for carrying a variable-length SaF/SAI frame on this link — see that project's CLAUDE.md. The IL/CTC/status gateways still relay at a fixed width; the same fix applies there when their own links carry protected frames.
  • Simulators. The Train and IL simulators and the RBC_Test_CommServer must speak the same protection (Python and C implementations checked against the same test vectors), otherwise the test environment cannot exercise the real path.
  • Sizes and timing. The relay channels and message_size values grow by the safety-layer header and MAC; the MAC computation must fit in the cycle budget (measure, do not assume).

Dependencies

Platform_Protocol_SafeComm is partly built (docs/safety/SUBSET_MAPPING.dox): the DES / 3DES engine, the 3DES CBC-MAC, the KSMAC derivation and the AU1 to AU3 handshake exist and pass their tests, and the DES / 3DES engine is verified by known answers (tests/test_mac_kat.c). What is missing: the official Subset-037 / Subset-098 vectors (the MAC padding, the KSMAC derivation and the PDU layouts are the project's constructions until they are checked against the controlled documents), supervision timers, a verified replay window, and the two profiles. The build-out order is in its ADR-003.

Transport binding, done for the channel-service case**: safecomm_transport_from_channel_service() wraps an already-open, caller-owned rte_channel_service_t. The CMake gap that blocked RBC_GP from depending on this library at all is fixed: Platform_Protocol_SafeComm now detects rte::oal/rte::channels already existing in the same CMake project (a consumer that add_subdirectory()'s Platform_RTE before add_subdirectory()'ing this library, which is exactly RBC_GP's default, source-build consumption pattern for every other dependency) and enables the framework path with no flag needed; its own install(EXPORT ...) step is now guarded the same way Platform_RTE's already is, so a consumer's cmake --install doesn't try to export a sibling-source target it has no import info for. Verified for real, not just by inspection: a scratch consumer project add_subdirectory()-ing both libraries together (the exact shape RBC_GP needs) auto-detects the framework with no flag, a probe program linking safecomm::cfm calls safecomm_transport_from_channel_service() and gets SAFECOMM_STATUS_OK (the real code path), and cmake --install from that consumer completes with no export errors — plus the two pre-existing consumption paths (standalone, and SAFECOMM_USE_INSTALLED_FRAMEWORK=ON against a real installed dist/) still both pass their 9/9 ctest unchanged. Done (2026-09-23): RBC_GP's own CMakeLists.txt now has an add_subdirectory(Platform_Protocol_SafeComm) block (mirroring the existing RTE_POSIX_OSADAPTER_DIR/DDS blocks, including forcing SAFECOMM_BUILD_TESTS=OFF the same way RTE_BUILD_TESTS is forced off for the framework block). The library builds as part of RBC_GP now, but nothing links against its targets yet — that's step 3 below.

Plan

  1. Library. DES / 3DES known-answer tests: done. Next: obtain the Subset-037 / Subset-098 text and vectors and check the MAC padding, the KSMAC derivation and the PDU layouts against them; then supervision timers and a verified replay window; then the two profiles (train, IL). Coverage to the target; constant-time MAC comparison.
  2. Test path. Python (RBC_Test_Sim_Core) and RBC_Test_CommServer implementations against the same vectors; the local and Docker environments run with protection switchable.
  3. Vital termination on the train link. safecomm::safety inside A and B; gateway relays protected frames; scenario suites pass with protection on. First increment done (2026-09-28), off by default:
    • Library (Platform_Protocol_SafeComm): a frame-driven responder API (one received frame in, at most one frame out, no blocking, REQ-SC-SAF-040..045) and a caller-supplied responder random RB. The library's own generator is a predictable, process-global LCG: two 2oo2 channels would derive different session keys. Also fixed a 64-byte MAC buffer that capped Sa-DATA user data at 54 bytes.
    • Platform: rte_random_fill() (Platform_RTE OAL seam, REQ-OAL-RANDOM-*), backed by getentropy() in Platform_OS_POSIX.
    • RBC_GP: A draws RB and shares it with B over the peer link, so both emit byte-identical AU2/AR/Sa-DATA frames (the gateway forwards one and drops the duplicate); unprotected ERTMS frames are dropped and no reply is sent unprotected while it is on; Subset-037 supervision on the cycle clock.
    • Second increment (2026-09-29): the train sim speaks SaF (RBC_Test_Sim_Core saf_train_link.py), switched on for the Docker stack by RTE_SAFECOMM_TRAIN_RBC_ID with a test-only key file; the full scenario suite passed with it on. Replies echo the train's T_TRAIN so A and B stay byte-identical; an RBC that lost a train's connection answers its Sa-DATA with a Sa-DISCONNECT and the train re-handshakes and resends.
    • Still open for this step: SaF in the IL sim and RBC_Test_CommServer; SaF session transfer to a standby site (a failover makes every train reconnect); the flat P0/M136 scheme.
  4. IL link. IL profile; GA's IL adapter reads verified application data only.
  5. Key and identity provisioning in the specific application; installer and configuration.
  6. Remove the plain path on these two links; update the wire mirror, sync_wire_catalog.py, the safety cases and the SRS.

Impact on the safety cases: SC-02 (protocol evidence), SC-03 (integration), SC-04 and SC-05 (claims REQ-SC-001 to REQ-SC-004), SC-06 (keys).