Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
sapi_dual_msgchannel.c
Go to the documentation of this file.
1
7
9
11
13
15
17
18
22{
23 if ((channel == NULL) || (config == NULL) || (config->link == NULL))
24 {
26 }
27
28 channel->link = config->link;
29 channel->sender_id = config->sender_id;
30 channel->expected_peer_id = config->expected_peer_id;
31 channel->next_sequence = 0U;
32 channel->expected_sequence = 0U;
33
34 return SAPI_STATUS_OK;
35}
36
38 const uint8_t *payload,
39 uint8_t payload_size,
40 sapi_duration_ms_t timeout_ms,
41 uint32_t *out_sequence)
42{
44 sapi_status_t status;
45
46 if (channel == NULL)
47 {
49 }
50 if ((payload == NULL) && (payload_size != 0U))
51 {
53 }
54
55 status = sapi_checksum_vital_message_create(&frame, channel->sender_id, channel->next_sequence, payload,
56 (size_t)payload_size);
57 if (status != SAPI_STATUS_OK)
58 {
59 return status;
60 }
61
62 status = sapi_netlink_send(channel->link, &frame, sizeof(frame), timeout_ms);
63 if (status != SAPI_STATUS_OK)
64 {
65 /* channel->next_sequence intentionally NOT advanced on failure -
66 * see this function's own doc: a retry reuses the same
67 * sequence_number rather than silently skipping ahead. */
68 return status;
69 }
70
71 if (out_sequence != NULL)
72 {
73 *out_sequence = channel->next_sequence;
74 }
75 channel->next_sequence++;
76
77 return SAPI_STATUS_OK;
78}
79
81 uint8_t *out_payload,
82 uint8_t payload_max_size,
83 sapi_duration_ms_t timeout_ms,
84 uint8_t *out_payload_size,
85 uint32_t *out_sequence)
86{
88 sapi_status_t status;
89
90 if ((channel == NULL) || (out_payload == NULL) || (out_payload_size == NULL) || (payload_max_size == 0U))
91 {
93 }
94
95 status = sapi_netlink_receive(channel->link, &frame, sizeof(frame), timeout_ms);
96 if (status != SAPI_STATUS_OK)
97 {
98 return status;
99 }
100
101 /* Masquerade defense (ADR-020 section 1): sapi_checksum_vital_message_
102 * verify() below checks CRC-64 and sequence continuity but has no
103 * concept of "which peer is this supposed to be" - that check is this
104 * layer's own responsibility. Checked before the CRC/sequence
105 * verify() call so a wrong-sender frame is reported distinctly
106 * (SAPI_STATUS_HARDWARE_FAULT) rather than folded into the generic
107 * SAPI_STATUS_DATA_CORRUPTION a corrupted-but-correctly-addressed
108 * frame gets. */
109 if (frame.sender_id != channel->expected_peer_id)
110 {
112 }
113
114 status = sapi_checksum_vital_message_verify(&frame, channel->expected_sequence, out_payload, (size_t)payload_max_size,
115 out_payload_size);
116 if (status != SAPI_STATUS_OK)
117 {
118 /* channel->expected_sequence intentionally left unchanged on
119 * failure - see sapi_dual_msgchannel_reset_sequence()'s own doc
120 * for the deliberate recovery path after a link (re)establishes,
121 * rather than silently resyncing here and weakening the
122 * anti-replay/anti-reorder defense this check exists for. */
123 return status;
124 }
125
126 if (out_sequence != NULL)
127 {
128 *out_sequence = frame.sequence_number;
129 }
130 channel->expected_sequence = frame.sequence_number + 1U;
131
132 return SAPI_STATUS_OK;
133}
134
136{
137 if (channel == NULL)
138 {
140 }
141
142 channel->next_sequence = 0U;
143 channel->expected_sequence = 0U;
144
145 return SAPI_STATUS_OK;
146}
sapi_status_t sapi_checksum_vital_message_verify(const sapi_vital_message_t *msg, uint32_t expected_sequence, uint8_t *payload_out, size_t payload_max_size, uint8_t *payload_size_out)
Verify vital channel message and extract payload.
sapi_status_t sapi_checksum_vital_message_create(sapi_vital_message_t *msg_out, uint32_t sender_id, uint32_t sequence, const uint8_t *payload, size_t payload_size)
Create vital channel message with CRC.
sapi_status_t sapi_dual_msgchannel_send(sapi_dual_msgchannel_t *channel, const uint8_t *payload, uint8_t payload_size, sapi_duration_ms_t timeout_ms, uint32_t *out_sequence)
Wraps payload in a sapi_vital_message_t (this channel's own sender_id and next sequence_number) and s...
sapi_status_t sapi_dual_msgchannel_init(sapi_dual_msgchannel_t *channel, const sapi_dual_msgchannel_config_t *config)
Initializes a sapi_dual_msgchannel_t: starts both sequence counters at 0.
sapi_status_t sapi_dual_msgchannel_reset_sequence(sapi_dual_msgchannel_t *channel)
Resets both sequence counters to 0. Intended to be called by the caller (typically sapi_dual_channel_...
sapi_status_t sapi_dual_msgchannel_receive(sapi_dual_msgchannel_t *channel, uint8_t *out_payload, uint8_t payload_max_size, sapi_duration_ms_t timeout_ms, uint8_t *out_payload_size, uint32_t *out_sequence)
Receives one frame over config->link, blocking at most timeout_ms, verifies its CRC-64 and sequence c...
sapi_status_t
Common result/status codes.
Definition sapi_status.h:27
@ SAPI_STATUS_HARDWARE_FAULT
Definition sapi_status.h:36
@ SAPI_STATUS_INVALID_PARAM
Definition sapi_status.h:29
@ SAPI_STATUS_OK
Definition sapi_status.h:28
uint32_t sapi_duration_ms_t
Definition sapi_types.h:27
"Channel" layer of ADR-020: one EN 50159-defended message channel over one already-open sapi_netlink_...
Configuration for sapi_dual_msgchannel_init().
One sapi_dual_msgchannel_t instance's state. Caller-owned storage (REQ-DUAL-MSGCHANNEL-001); opaque i...
sapi_netlink_handle_t link
Vital channel message with integrated CRC-64.