statime/datastructures/messages/
mod.rs

1//! Ptp network messages
2
3pub(crate) use announce::*;
4pub(crate) use delay_req::*;
5pub(crate) use delay_resp::*;
6pub(crate) use follow_up::*;
7pub use header::*;
8pub(crate) use p_delay_req::*;
9pub(crate) use p_delay_resp::*;
10pub(crate) use p_delay_resp_follow_up::*;
11pub(crate) use sync::*;
12
13use self::{management::ManagementMessage, signalling::SignalingMessage};
14use super::{
15    common::{PortIdentity, TimeInterval, TlvSet, WireTimestamp},
16    datasets::InternalDefaultDS,
17    WireFormatError,
18};
19use crate::{
20    config::LeapIndicator,
21    ptp_instance::PtpInstanceState,
22    time::{Interval, Time},
23};
24
25mod announce;
26mod control_field;
27mod delay_req;
28mod delay_resp;
29mod follow_up;
30mod header;
31mod management;
32mod p_delay_req;
33mod p_delay_resp;
34mod p_delay_resp_follow_up;
35mod signalling;
36mod sync;
37
38/// Maximum length of a packet
39///
40/// This can be used to preallocate buffers that can always fit packets send by
41/// `statime`.
42pub const MAX_DATA_LEN: usize = 1024;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45#[repr(u8)]
46pub enum MessageType {
47    Sync = 0x0,
48    DelayReq = 0x1,
49    PDelayReq = 0x2,
50    PDelayResp = 0x3,
51    FollowUp = 0x8,
52    DelayResp = 0x9,
53    PDelayRespFollowUp = 0xa,
54    Announce = 0xb,
55    Signaling = 0xc,
56    Management = 0xd,
57}
58
59pub struct EnumConversionError;
60
61impl TryFrom<u8> for MessageType {
62    type Error = EnumConversionError;
63
64    fn try_from(value: u8) -> Result<Self, Self::Error> {
65        use MessageType::*;
66
67        match value {
68            0x0 => Ok(Sync),
69            0x1 => Ok(DelayReq),
70            0x2 => Ok(PDelayReq),
71            0x3 => Ok(PDelayResp),
72            0x8 => Ok(FollowUp),
73            0x9 => Ok(DelayResp),
74            0xa => Ok(PDelayRespFollowUp),
75            0xb => Ok(Announce),
76            0xc => Ok(Signaling),
77            0xd => Ok(Management),
78            _ => Err(EnumConversionError),
79        }
80    }
81}
82
83#[cfg(feature = "fuzz")]
84pub use fuzz::FuzzMessage;
85
86#[cfg(feature = "fuzz")]
87#[allow(missing_docs)] // These are only used for internal fuzzing
88mod fuzz {
89    use super::*;
90    use crate::datastructures::{common::Tlv, WireFormatError};
91
92    #[derive(Debug, Clone, PartialEq, Eq)]
93    pub struct FuzzMessage<'a> {
94        inner: Message<'a>,
95    }
96
97    #[derive(Debug, Clone, PartialEq, Eq)]
98    pub struct FuzzTlv<'a>(Tlv<'a>);
99
100    impl<'a> FuzzMessage<'a> {
101        pub fn deserialize(buffer: &'a [u8]) -> Result<Self, impl std::error::Error> {
102            Ok::<FuzzMessage, WireFormatError>(FuzzMessage {
103                inner: Message::deserialize(buffer)?,
104            })
105        }
106
107        pub fn serialize(&self, buffer: &mut [u8]) -> Result<usize, impl std::error::Error> {
108            self.inner.serialize(buffer)
109        }
110
111        pub fn tlv(&self) -> impl Iterator<Item = FuzzTlv<'_>> + '_ {
112            self.inner.suffix.tlv().map(FuzzTlv)
113        }
114    }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq)]
118pub(crate) struct Message<'a> {
119    pub(crate) header: Header,
120    pub(crate) body: MessageBody,
121    pub(crate) suffix: TlvSet<'a>,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub(crate) enum MessageBody {
126    Sync(SyncMessage),
127    DelayReq(DelayReqMessage),
128    PDelayReq(PDelayReqMessage),
129    PDelayResp(PDelayRespMessage),
130    FollowUp(FollowUpMessage),
131    DelayResp(DelayRespMessage),
132    PDelayRespFollowUp(PDelayRespFollowUpMessage),
133    Announce(AnnounceMessage),
134    Signaling(SignalingMessage),
135    Management(ManagementMessage),
136}
137
138impl MessageBody {
139    fn wire_size(&self) -> usize {
140        match &self {
141            MessageBody::Sync(m) => m.content_size(),
142            MessageBody::DelayReq(m) => m.content_size(),
143            MessageBody::PDelayReq(m) => m.content_size(),
144            MessageBody::PDelayResp(m) => m.content_size(),
145            MessageBody::FollowUp(m) => m.content_size(),
146            MessageBody::DelayResp(m) => m.content_size(),
147            MessageBody::PDelayRespFollowUp(m) => m.content_size(),
148            MessageBody::Announce(m) => m.content_size(),
149            MessageBody::Signaling(m) => m.content_size(),
150            MessageBody::Management(m) => m.content_size(),
151        }
152    }
153
154    fn content_type(&self) -> MessageType {
155        match self {
156            MessageBody::Sync(_) => MessageType::Sync,
157            MessageBody::DelayReq(_) => MessageType::DelayReq,
158            MessageBody::PDelayReq(_) => MessageType::PDelayReq,
159            MessageBody::PDelayResp(_) => MessageType::PDelayResp,
160            MessageBody::FollowUp(_) => MessageType::FollowUp,
161            MessageBody::DelayResp(_) => MessageType::DelayResp,
162            MessageBody::PDelayRespFollowUp(_) => MessageType::PDelayRespFollowUp,
163            MessageBody::Announce(_) => MessageType::Announce,
164            MessageBody::Signaling(_) => MessageType::Signaling,
165            MessageBody::Management(_) => MessageType::Management,
166        }
167    }
168
169    pub(crate) fn serialize(&self, buffer: &mut [u8]) -> Result<usize, super::WireFormatError> {
170        match &self {
171            MessageBody::Sync(m) => m.serialize_content(buffer)?,
172            MessageBody::DelayReq(m) => m.serialize_content(buffer)?,
173            MessageBody::PDelayReq(m) => m.serialize_content(buffer)?,
174            MessageBody::PDelayResp(m) => m.serialize_content(buffer)?,
175            MessageBody::FollowUp(m) => m.serialize_content(buffer)?,
176            MessageBody::DelayResp(m) => m.serialize_content(buffer)?,
177            MessageBody::PDelayRespFollowUp(m) => m.serialize_content(buffer)?,
178            MessageBody::Announce(m) => m.serialize_content(buffer)?,
179            MessageBody::Signaling(m) => m.serialize_content(buffer)?,
180            MessageBody::Management(m) => m.serialize_content(buffer)?,
181        }
182
183        Ok(self.wire_size())
184    }
185
186    pub(crate) fn deserialize(
187        message_type: MessageType,
188        header: &Header,
189        buffer: &[u8],
190    ) -> Result<Self, super::WireFormatError> {
191        let body = match message_type {
192            MessageType::Sync => MessageBody::Sync(SyncMessage::deserialize_content(buffer)?),
193            MessageType::DelayReq => {
194                MessageBody::DelayReq(DelayReqMessage::deserialize_content(buffer)?)
195            }
196            MessageType::PDelayReq => {
197                MessageBody::PDelayReq(PDelayReqMessage::deserialize_content(buffer)?)
198            }
199            MessageType::PDelayResp => {
200                MessageBody::PDelayResp(PDelayRespMessage::deserialize_content(buffer)?)
201            }
202            MessageType::FollowUp => {
203                MessageBody::FollowUp(FollowUpMessage::deserialize_content(buffer)?)
204            }
205            MessageType::DelayResp => {
206                MessageBody::DelayResp(DelayRespMessage::deserialize_content(buffer)?)
207            }
208            MessageType::PDelayRespFollowUp => MessageBody::PDelayRespFollowUp(
209                PDelayRespFollowUpMessage::deserialize_content(buffer)?,
210            ),
211            MessageType::Announce => {
212                MessageBody::Announce(AnnounceMessage::deserialize_content(*header, buffer)?)
213            }
214            MessageType::Signaling => {
215                MessageBody::Signaling(SignalingMessage::deserialize_content(buffer)?)
216            }
217            MessageType::Management => {
218                MessageBody::Management(ManagementMessage::deserialize_content(buffer)?)
219            }
220        };
221
222        Ok(body)
223    }
224}
225
226fn base_header(
227    default_ds: &InternalDefaultDS,
228    port_identity: PortIdentity,
229    sequence_id: u16,
230    minor_ptp_version: u8,
231) -> Header {
232    Header {
233        sdo_id: default_ds.sdo_id,
234        domain_number: default_ds.domain_number,
235        source_port_identity: port_identity,
236        sequence_id,
237        ..Header::new(minor_ptp_version)
238    }
239}
240
241/// Checks whether message is of PTP revision compatible with Statime
242pub fn is_compatible(buffer: &[u8]) -> bool {
243    // this ensures that versionPTP in the header is 2
244    // it will never happen in PTPv1 packets because this octet is the LSB of
245    // versionPTP there
246    (buffer.len() >= 2) && (buffer[1] & 0xf) == 2
247}
248
249impl Message<'_> {
250    pub(crate) fn sync(
251        default_ds: &InternalDefaultDS,
252        port_identity: PortIdentity,
253        sequence_id: u16,
254        minor_ptp_version: u8,
255    ) -> Self {
256        let header = Header {
257            two_step_flag: true,
258            ..base_header(default_ds, port_identity, sequence_id, minor_ptp_version)
259        };
260
261        Message {
262            header,
263            body: MessageBody::Sync(SyncMessage {
264                origin_timestamp: Default::default(),
265            }),
266            suffix: TlvSet::default(),
267        }
268    }
269
270    pub(crate) fn follow_up(
271        default_ds: &InternalDefaultDS,
272        port_identity: PortIdentity,
273        sequence_id: u16,
274        timestamp: Time,
275        minor_ptp_version: u8,
276    ) -> Self {
277        let header = Header {
278            correction_field: timestamp.subnano(),
279            ..base_header(default_ds, port_identity, sequence_id, minor_ptp_version)
280        };
281
282        Message {
283            header,
284            body: MessageBody::FollowUp(FollowUpMessage {
285                precise_origin_timestamp: timestamp.into(),
286            }),
287            suffix: TlvSet::default(),
288        }
289    }
290
291    pub(crate) fn announce(
292        global: &PtpInstanceState,
293        port_identity: PortIdentity,
294        sequence_id: u16,
295        minor_ptp_version: u8,
296    ) -> Self {
297        let time_properties_ds = &global.time_properties_ds;
298
299        let header = Header {
300            leap59: time_properties_ds.leap_indicator == LeapIndicator::Leap59,
301            leap61: time_properties_ds.leap_indicator == LeapIndicator::Leap61,
302            current_utc_offset_valid: time_properties_ds.current_utc_offset.is_some(),
303            ptp_timescale: time_properties_ds.ptp_timescale,
304            time_tracable: time_properties_ds.time_traceable,
305            frequency_tracable: time_properties_ds.frequency_traceable,
306            ..base_header(
307                &global.default_ds,
308                port_identity,
309                sequence_id,
310                minor_ptp_version,
311            )
312        };
313
314        let body = MessageBody::Announce(AnnounceMessage {
315            header,
316            origin_timestamp: Default::default(),
317            current_utc_offset: time_properties_ds.current_utc_offset.unwrap_or_default(),
318            grandmaster_priority_1: global.parent_ds.grandmaster_priority_1,
319            grandmaster_clock_quality: global.parent_ds.grandmaster_clock_quality,
320            grandmaster_priority_2: global.parent_ds.grandmaster_priority_2,
321            grandmaster_identity: global.parent_ds.grandmaster_identity,
322            steps_removed: global.current_ds.steps_removed,
323            time_source: time_properties_ds.time_source,
324        });
325
326        Message {
327            header,
328            body,
329            suffix: TlvSet::default(),
330        }
331    }
332
333    pub(crate) fn delay_req(
334        default_ds: &InternalDefaultDS,
335        port_identity: PortIdentity,
336        sequence_id: u16,
337        minor_ptp_version: u8,
338    ) -> Self {
339        let header = Header {
340            log_message_interval: 0x7f,
341            ..base_header(default_ds, port_identity, sequence_id, minor_ptp_version)
342        };
343
344        Message {
345            header,
346            body: MessageBody::DelayReq(DelayReqMessage {
347                origin_timestamp: WireTimestamp::default(),
348            }),
349            suffix: TlvSet::default(),
350        }
351    }
352
353    pub(crate) fn delay_resp(
354        request_header: Header,
355        request: DelayReqMessage,
356        port_identity: PortIdentity,
357        min_delay_req_interval: Interval,
358        timestamp: Time,
359    ) -> Self {
360        // TODO is it really correct that we don't use any of the data?
361        let _ = request;
362
363        let header = Header {
364            two_step_flag: false,
365            source_port_identity: port_identity,
366            correction_field: TimeInterval(
367                request_header.correction_field.0 + timestamp.subnano().0,
368            ),
369            log_message_interval: min_delay_req_interval.as_log_2(),
370            ..request_header
371        };
372
373        let body = MessageBody::DelayResp(DelayRespMessage {
374            receive_timestamp: timestamp.into(),
375            requesting_port_identity: request_header.source_port_identity,
376        });
377
378        Message {
379            header,
380            body,
381            suffix: TlvSet::default(),
382        }
383    }
384
385    pub(crate) fn pdelay_req(
386        default_ds: &InternalDefaultDS,
387        port_identity: PortIdentity,
388        sequence_id: u16,
389        minor_ptp_version: u8,
390    ) -> Self {
391        Message {
392            header: base_header(default_ds, port_identity, sequence_id, minor_ptp_version),
393            body: MessageBody::PDelayReq(PDelayReqMessage {
394                origin_timestamp: WireTimestamp::default(),
395            }),
396            suffix: TlvSet::default(),
397        }
398    }
399
400    pub(crate) fn pdelay_resp(
401        default_ds: &InternalDefaultDS,
402        port_identity: PortIdentity,
403        request_header: Header,
404        timestamp: Time,
405        minor_ptp_version: u8,
406    ) -> Self {
407        // We implement Option B from IEEE 1588-2019 page 202
408        Message {
409            header: Header {
410                two_step_flag: true,
411                correction_field: request_header.correction_field,
412                ..base_header(
413                    default_ds,
414                    port_identity,
415                    request_header.sequence_id,
416                    minor_ptp_version,
417                )
418            },
419            body: MessageBody::PDelayResp(PDelayRespMessage {
420                request_receive_timestamp: timestamp.into(),
421                requesting_port_identity: request_header.source_port_identity,
422            }),
423            suffix: TlvSet::default(),
424        }
425    }
426
427    pub(crate) fn pdelay_resp_follow_up(
428        default_ds: &InternalDefaultDS,
429        port_identity: PortIdentity,
430        requestor_identity: PortIdentity,
431        sequence_id: u16,
432        timestamp: Time,
433        minor_ptp_version: u8,
434    ) -> Self {
435        Message {
436            header: base_header(default_ds, port_identity, sequence_id, minor_ptp_version),
437            body: MessageBody::PDelayRespFollowUp(PDelayRespFollowUpMessage {
438                response_origin_timestamp: timestamp.into(),
439                requesting_port_identity: requestor_identity,
440            }),
441            suffix: TlvSet::default(),
442        }
443    }
444}
445
446impl<'a> Message<'a> {
447    pub(crate) fn header(&self) -> &Header {
448        &self.header
449    }
450
451    /// The byte size on the wire of this message
452    pub(crate) fn wire_size(&self) -> usize {
453        self.header.wire_size() + self.body.wire_size() + self.suffix.wire_size()
454    }
455
456    /// Serializes the object into the PTP wire format.
457    ///
458    /// Returns the used buffer size that contains the message or an error.
459    pub(crate) fn serialize(&self, buffer: &mut [u8]) -> Result<usize, super::WireFormatError> {
460        let (header, rest) = buffer.split_at_mut(34);
461        let (body, tlv) = rest.split_at_mut(self.body.wire_size());
462
463        self.header
464            .serialize_header(
465                self.body.content_type(),
466                self.body.wire_size() + self.suffix.wire_size(),
467                header,
468            )
469            .unwrap();
470
471        self.body.serialize(body).unwrap();
472
473        self.suffix.serialize(tlv).unwrap();
474
475        Ok(self.wire_size())
476    }
477
478    /// Deserializes a message from the PTP wire format.
479    ///
480    /// Returns the message or an error.
481    pub(crate) fn deserialize(buffer: &'a [u8]) -> Result<Self, super::WireFormatError> {
482        let header_data = Header::deserialize_header(buffer)?;
483
484        if header_data.message_length < 34 {
485            return Err(WireFormatError::Invalid);
486        }
487
488        // Ensure we have the entire message and ignore potential padding
489        // Skip the header bytes and only keep the content
490        let content_buffer = buffer
491            .get(34..(header_data.message_length as usize))
492            .ok_or(WireFormatError::BufferTooShort)?;
493
494        let body = MessageBody::deserialize(
495            header_data.message_type,
496            &header_data.header,
497            content_buffer,
498        )?;
499
500        let tlv_buffer = &content_buffer
501            .get(body.wire_size()..)
502            .ok_or(super::WireFormatError::BufferTooShort)?;
503        let suffix = TlvSet::deserialize(tlv_buffer)?;
504
505        Ok(Message {
506            header: header_data.header,
507            body,
508            suffix,
509        })
510    }
511}