autosar_data_abstraction/communication/pdu/
secured_ipdu.rs1use crate::communication::{
2 AbstractIpdu, AbstractPdu, AbstractPhysicalChannel, IPdu, Pdu, PduToFrameMapping, PduTriggering,
3};
4use crate::{
5 AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
6 get_reference_parents,
7};
8use autosar_data::{Element, ElementName};
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct SecuredIPdu(Element);
15abstraction_element!(SecuredIPdu, SecuredIPdu);
16impl IdentifiableAbstractionElement for SecuredIPdu {}
17
18impl SecuredIPdu {
19 pub(crate) fn new(
20 name: &str,
21 package: &ArPackage,
22 length: u32,
23 secure_props: &SecureCommunicationProps,
24 ) -> Result<Self, AutosarAbstractionError> {
25 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
26 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::SecuredIPdu, name)?;
27 let secured_ipdu = Self(elem_pdu);
28 secured_ipdu.set_length(length)?;
29 secured_ipdu.set_secure_communication_props(secure_props)?;
30
31 Ok(secured_ipdu)
32 }
33
34 pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
36 let opt_pdu_triggering = self.payload_pdu_triggering();
37
38 for pdu_triggering in self.pdu_triggerings() {
40 let _ = pdu_triggering.element().remove_sub_element_kind(ElementName::IPduRef);
41 let _ = pdu_triggering.remove(deep);
42 }
43
44 let ref_parents = get_reference_parents(self.element())?;
45
46 AbstractionElement::remove(self, deep)?;
47
48 for (named_parent, _parent) in ref_parents {
49 if named_parent.element_name() == ElementName::PduToFrameMapping
50 && let Ok(pdu_to_frame_mapping) = PduToFrameMapping::try_from(named_parent)
51 {
52 pdu_to_frame_mapping.remove(deep)?;
53 }
54 }
55
56 if let Some(pdu_triggering) = opt_pdu_triggering {
58 pdu_triggering.remove(deep)?;
59 }
60
61 Ok(())
62 }
63
64 pub fn set_secure_communication_props(
66 &self,
67 props: &SecureCommunicationProps,
68 ) -> Result<(), AutosarAbstractionError> {
69 SecureCommunicationProps::set_props(self.element(), props)
70 }
71
72 #[must_use]
74 pub fn secure_communication_props(&self) -> Option<SecureCommunicationProps> {
75 SecureCommunicationProps::get_props(self.element())
76 }
77
78 pub fn set_use_as_cryptographic_ipdu(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
80 if let Some(value) = value {
81 self.element()
82 .get_or_create_sub_element(ElementName::UseAsCryptographicIPdu)?
83 .set_character_data(value.to_string())?;
84 } else {
85 let _ = self
86 .element()
87 .remove_sub_element_kind(ElementName::UseAsCryptographicIPdu);
88 }
89 Ok(())
90 }
91
92 #[must_use]
94 pub fn use_as_cryptographic_ipdu(&self) -> Option<bool> {
95 self.element()
96 .get_sub_element(ElementName::UseAsCryptographicIPdu)?
97 .character_data()?
98 .parse_bool()
99 }
100
101 pub fn set_payload_ipdu<T: AbstractIpdu + AbstractPdu, U: AbstractPhysicalChannel>(
106 &self,
107 ipdu: &T,
108 physical_channel: &U,
109 ) -> Result<PduTriggering, AutosarAbstractionError> {
110 if let Some(ppt) = self.payload_pdu_triggering() {
111 ppt.remove(false)?;
112 }
113 let pdu_triggering = PduTriggering::new(&ipdu.clone().into(), &physical_channel.clone().into())?;
114 self.0
115 .get_or_create_sub_element(ElementName::PayloadRef)?
116 .set_reference_target(pdu_triggering.element())?;
117
118 Ok(pdu_triggering)
119 }
120
121 pub fn set_payload_pdu_triggering(&self, pdu_triggering: &PduTriggering) -> Result<(), AutosarAbstractionError> {
127 if let Some(ppt) = self.payload_pdu_triggering()
128 && ppt != *pdu_triggering
129 {
130 ppt.remove(false)?;
131 }
132 self.0
133 .get_or_create_sub_element(ElementName::PayloadRef)?
134 .set_reference_target(pdu_triggering.element())?;
135 Ok(())
136 }
137
138 #[must_use]
140 pub fn payload_pdu_triggering(&self) -> Option<PduTriggering> {
141 let elem = self.0.get_sub_element(ElementName::PayloadRef)?;
142 PduTriggering::try_from(elem.get_reference_target().ok()?).ok()
143 }
144}
145
146impl AbstractPdu for SecuredIPdu {}
147
148impl AbstractIpdu for SecuredIPdu {}
149
150impl From<SecuredIPdu> for Pdu {
151 fn from(value: SecuredIPdu) -> Self {
152 Pdu::SecuredIPdu(value)
153 }
154}
155
156impl From<SecuredIPdu> for IPdu {
157 fn from(value: SecuredIPdu) -> Self {
158 IPdu::SecuredIPdu(value)
159 }
160}
161
162#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
166pub struct SecureCommunicationProps {
167 pub auth_data_freshness_length: Option<u32>,
169 pub auth_data_freshness_start_position: Option<u32>,
171 pub authentication_build_attempts: Option<u32>,
173 pub authentication_retries: Option<u32>,
175 pub data_id: Option<u32>,
177 pub freshness_value_id: Option<u32>,
179 pub message_link_length: Option<u32>,
181 pub message_link_position: Option<u32>,
183 pub secondary_freshness_value_id: Option<u32>,
185 pub secured_area_length: Option<u32>,
187 pub secured_area_offset: Option<u32>,
189}
190
191impl SecureCommunicationProps {
192 pub(crate) fn set_props(
193 element: &Element,
194 props: &SecureCommunicationProps,
195 ) -> Result<(), AutosarAbstractionError> {
196 let sub_elem = element.get_or_create_sub_element(ElementName::SecureCommunicationProps)?;
197 if let Some(value) = props.auth_data_freshness_length {
198 sub_elem
199 .create_sub_element(ElementName::AuthDataFreshnessLength)?
200 .set_character_data(value as u64)?;
201 }
202 if let Some(value) = props.auth_data_freshness_start_position {
203 sub_elem
204 .create_sub_element(ElementName::AuthDataFreshnessStartPosition)?
205 .set_character_data(value as u64)?;
206 }
207 if let Some(value) = props.authentication_build_attempts {
208 sub_elem
209 .create_sub_element(ElementName::AuthenticationBuildAttempts)?
210 .set_character_data(value as u64)?;
211 }
212 if let Some(value) = props.authentication_retries {
213 sub_elem
214 .create_sub_element(ElementName::AuthenticationRetries)?
215 .set_character_data(value as u64)?;
216 }
217 if let Some(value) = props.data_id {
218 sub_elem
219 .create_sub_element(ElementName::DataId)?
220 .set_character_data(value as u64)?;
221 }
222 if let Some(value) = props.freshness_value_id {
223 sub_elem
224 .create_sub_element(ElementName::FreshnessValueId)?
225 .set_character_data(value as u64)?;
226 }
227 if let Some(value) = props.message_link_length {
228 sub_elem
229 .create_sub_element(ElementName::MessageLinkLength)?
230 .set_character_data(value as u64)?;
231 }
232 if let Some(value) = props.message_link_position {
233 sub_elem
234 .create_sub_element(ElementName::MessageLinkPosition)?
235 .set_character_data(value as u64)?;
236 }
237 if let Some(value) = props.secondary_freshness_value_id {
238 sub_elem
239 .create_sub_element(ElementName::SecondaryFreshnessValueId)?
240 .set_character_data(value as u64)?;
241 }
242 if let Some(value) = props.secured_area_length {
243 sub_elem
244 .create_sub_element(ElementName::SecuredAreaLength)?
245 .set_character_data(value as u64)?;
246 }
247 if let Some(value) = props.secured_area_offset {
248 sub_elem
249 .create_sub_element(ElementName::SecuredAreaOffset)?
250 .set_character_data(value as u64)?;
251 }
252 Ok(())
253 }
254
255 pub(crate) fn get_props(element: &Element) -> Option<SecureCommunicationProps> {
256 let sub_elem = element.get_sub_element(ElementName::SecureCommunicationProps)?;
257 Some(SecureCommunicationProps {
258 auth_data_freshness_length: sub_elem
259 .get_sub_element(ElementName::AuthDataFreshnessLength)
260 .and_then(|elem| elem.character_data()?.parse_integer()),
261 auth_data_freshness_start_position: sub_elem
262 .get_sub_element(ElementName::AuthDataFreshnessStartPosition)
263 .and_then(|elem| elem.character_data()?.parse_integer()),
264 authentication_build_attempts: sub_elem
265 .get_sub_element(ElementName::AuthenticationBuildAttempts)
266 .and_then(|elem| elem.character_data()?.parse_integer()),
267 authentication_retries: sub_elem
268 .get_sub_element(ElementName::AuthenticationRetries)
269 .and_then(|elem| elem.character_data()?.parse_integer()),
270 data_id: sub_elem
271 .get_sub_element(ElementName::DataId)
272 .and_then(|elem| elem.character_data()?.parse_integer()),
273 freshness_value_id: sub_elem
274 .get_sub_element(ElementName::FreshnessValueId)
275 .and_then(|elem| elem.character_data()?.parse_integer()),
276 message_link_length: sub_elem
277 .get_sub_element(ElementName::MessageLinkLength)
278 .and_then(|elem| elem.character_data()?.parse_integer()),
279 message_link_position: sub_elem
280 .get_sub_element(ElementName::MessageLinkPosition)
281 .and_then(|elem| elem.character_data()?.parse_integer()),
282 secondary_freshness_value_id: sub_elem
283 .get_sub_element(ElementName::SecondaryFreshnessValueId)
284 .and_then(|elem| elem.character_data()?.parse_integer()),
285 secured_area_length: sub_elem
286 .get_sub_element(ElementName::SecuredAreaLength)
287 .and_then(|elem| elem.character_data()?.parse_integer()),
288 secured_area_offset: sub_elem
289 .get_sub_element(ElementName::SecuredAreaOffset)
290 .and_then(|elem| elem.character_data()?.parse_integer()),
291 })
292 }
293}
294
295#[cfg(test)]
298mod test {
299 use super::*;
300 use crate::{
301 AutosarModelAbstraction, ByteOrder, SystemCategory,
302 communication::{AbstractFrame, CanAddressingMode, CanFrameType},
303 };
304 use autosar_data::AutosarVersion;
305
306 #[test]
307 fn test_secured_ipdu() -> Result<(), AutosarAbstractionError> {
308 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
309 let package = model.get_or_create_package("/pkg1")?;
310 let system = package.create_system("System", SystemCategory::SystemExtract)?;
311 let can_cluster = system.create_can_cluster("Cluster", &package, None)?;
312 let can_channel = can_cluster.create_physical_channel("Channel")?;
313
314 let secure_communication_props = SecureCommunicationProps {
315 auth_data_freshness_length: Some(1),
316 auth_data_freshness_start_position: Some(2),
317 authentication_build_attempts: Some(3),
318 authentication_retries: Some(4),
319 data_id: Some(5),
320 freshness_value_id: Some(6),
321 message_link_length: Some(7),
322 message_link_position: Some(8),
323 secondary_freshness_value_id: Some(9),
324 secured_area_length: Some(10),
325 secured_area_offset: Some(11),
326 };
327 let secured_ipdu = system.create_secured_ipdu("SecuredIPdu", &package, 64, &secure_communication_props)?;
328 assert_eq!(
329 secured_ipdu.secure_communication_props(),
330 Some(secure_communication_props)
331 );
332 assert_eq!(secured_ipdu.use_as_cryptographic_ipdu(), None);
333 secured_ipdu.set_use_as_cryptographic_ipdu(Some(true))?;
334 assert_eq!(secured_ipdu.use_as_cryptographic_ipdu(), Some(true));
335 secured_ipdu.set_use_as_cryptographic_ipdu(Some(false))?;
336 assert_eq!(secured_ipdu.use_as_cryptographic_ipdu(), Some(false));
337 secured_ipdu.set_use_as_cryptographic_ipdu(None)?;
338 assert_eq!(secured_ipdu.use_as_cryptographic_ipdu(), None);
339
340 let payload_ipdu = system.create_isignal_ipdu("PayloadIPdu", &package, 64)?;
341 let pdu_triggering = secured_ipdu.set_payload_ipdu(&payload_ipdu, &can_channel)?;
342 assert_eq!(secured_ipdu.payload_pdu_triggering(), Some(pdu_triggering));
343
344 let external_ipdu = system.create_isignal_ipdu("ExternalIPdu", &package, 64)?;
345 let can_frame = system.create_can_frame("CanFrame", &package, 64)?;
346 can_channel
347 .trigger_frame(&can_frame, 0x101, CanAddressingMode::Standard, CanFrameType::CanFd)
348 .unwrap();
349 can_frame
350 .map_pdu(&external_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
351 .unwrap();
352 let external_pdu_triggering = &external_ipdu.pdu_triggerings()[0];
353 secured_ipdu.set_payload_pdu_triggering(external_pdu_triggering)?;
354 assert_eq!(
355 secured_ipdu.payload_pdu_triggering(),
356 Some(external_pdu_triggering.clone())
357 );
358
359 Ok(())
360 }
361}