Skip to main content

statime_wire/common/
tlv.rs

1use core::iter::FusedIterator;
2
3use crate::Error;
4
5/// A builder that can be used to create [`TlvSet`]
6#[derive(PartialEq, Eq)]
7pub struct TlvSetBuilder<'a> {
8    buffer: &'a mut [u8],
9    used: usize,
10}
11
12impl<'a> TlvSetBuilder<'a> {
13    /// Create a new builder with the given buffer as backing storage
14    pub fn new(buffer: &'a mut [u8]) -> Self {
15        Self { buffer, used: 0 }
16    }
17
18    /// Add a TLV to the builder.
19    ///
20    /// # Errors
21    /// Fails when the remaining buffer is too small for the TLV, or
22    /// when the TLV itself is larger than 2^16 bytes.
23    pub fn add(&mut self, tlv: &Tlv<'_>) -> Result<(), Error> {
24        tlv.serialize(&mut self.buffer[self.used..])?;
25        self.used += tlv.wire_size();
26        Ok(())
27    }
28
29    /// Create the actual [`TlvSet`]
30    #[must_use]
31    pub fn build(self) -> TlvSet<'a> {
32        TlvSet {
33            bytes: &self.buffer[..self.used],
34        }
35    }
36}
37
38/// A set of TLVs that can be iterated over.
39#[derive(Clone, PartialEq, Eq, Default)]
40pub struct TlvSet<'a> {
41    bytes: &'a [u8],
42}
43
44impl core::fmt::Debug for TlvSet<'_> {
45    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46        f.debug_struct("TlvSet")
47            .field("wire_size", &self.wire_size())
48            .field("bytes", &self.bytes)
49            .finish()
50    }
51}
52
53impl<'a> TlvSet<'a> {
54    pub(crate) fn wire_size(&self) -> usize {
55        // tlv should be an even number of octets!
56        debug_assert_eq!(self.bytes.len() % 2, 0);
57
58        self.bytes.len()
59    }
60
61    pub(crate) fn serialize(&self, buffer: &mut [u8]) -> Result<usize, Error> {
62        buffer
63            .get_mut(..self.bytes.len())
64            .ok_or(Error::BufferTooShort)?
65            .copy_from_slice(self.bytes);
66
67        Ok(self.bytes.len())
68    }
69
70    pub(crate) fn deserialize(mut buffer: &'a [u8]) -> Result<Self, Error> {
71        let original = buffer;
72        let mut total_length = 0;
73
74        while buffer.len() >= 4 {
75            let _tlv_type = TlvType::from_primitive(u16::from_be_bytes([buffer[0], buffer[1]]));
76            let length = u16::from_be_bytes([buffer[2], buffer[3]]) as usize;
77
78            if !length.is_multiple_of(2) {
79                return Err(Error::Invalid);
80            }
81
82            buffer = buffer.get(4 + length..).ok_or(Error::BufferTooShort)?;
83
84            total_length += 4 + length;
85        }
86
87        if !buffer.is_empty() {
88            return Err(Error::BufferTooShort);
89        }
90
91        Ok(Self {
92            bytes: &original[..total_length],
93        })
94    }
95
96    /// Iterator over all TLVs in the set which need to be propagated when
97    /// attached to announce messages.
98    pub fn announce_propagate_tlvs(&self) -> impl Iterator<Item = Tlv<'a>> + 'a {
99        self.tlvs().filter(|tlv| tlv.tlv_type.announce_propagate())
100    }
101
102    /// Iterator over all TLVs in the set.
103    pub fn tlvs(&self) -> impl Iterator<Item = Tlv<'a>> + 'a {
104        TlvSetIterator { buffer: self.bytes }
105    }
106}
107
108#[derive(Debug)]
109struct TlvSetIterator<'a> {
110    buffer: &'a [u8],
111}
112
113impl<'a> Iterator for TlvSetIterator<'a> {
114    type Item = Tlv<'a>;
115
116    fn next(&mut self) -> Option<Self::Item> {
117        if self.buffer.len() < 4 {
118            debug_assert_eq!(self.buffer.len(), 0);
119            return None;
120        }
121
122        // we've validated the buffer; this should never fail!
123        let tlv = Tlv::deserialize(self.buffer).unwrap();
124
125        self.buffer = &self.buffer[tlv.wire_size()..];
126
127        Some(tlv)
128    }
129}
130
131impl FusedIterator for TlvSetIterator<'_> {}
132
133/// A single TLV that can be afixed to a PTP message.
134#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct Tlv<'a> {
136    /// The type of this TLV.
137    pub tlv_type: TlvType,
138    /// The actual contents of the TLV.
139    ///
140    /// Note that this is of type [`Cow<'a, [u8]>`](std::borrow::Cow) instead
141    /// when the standard library feature is enabled.
142    #[cfg(not(feature = "std"))]
143    pub value: &'a [u8],
144    /// The actual contents of the TLV.
145    ///
146    /// Note that this is of type `&'a [u8]` instead when the standard library
147    /// feature is disabled.
148    #[cfg(feature = "std")]
149    pub value: std::borrow::Cow<'a, [u8]>,
150}
151
152impl<'a> Tlv<'a> {
153    pub(crate) fn wire_size(&self) -> usize {
154        4 + self.value.len()
155    }
156
157    pub(crate) fn serialize(&self, buffer: &mut [u8]) -> Result<(), Error> {
158        let len = u16::try_from(self.value.len()).map_err(|_| Error::Invalid)?;
159        buffer
160            .get_mut(0..2)
161            .ok_or(Error::BufferTooShort)?
162            .copy_from_slice(&self.tlv_type.to_primitive().to_be_bytes());
163        buffer
164            .get_mut(2..4)
165            .ok_or(Error::BufferTooShort)?
166            .copy_from_slice(&len.to_be_bytes());
167        buffer
168            .get_mut(4..)
169            .ok_or(Error::BufferTooShort)?
170            .get_mut(..self.value.len())
171            .ok_or(Error::BufferTooShort)?
172            .copy_from_slice(self.value.as_ref());
173
174        Ok(())
175    }
176
177    fn deserialize(buffer: &'a [u8]) -> Result<Self, Error> {
178        if buffer.len() < 4 {
179            return Err(Error::BufferTooShort);
180        }
181
182        let tlv_type = TlvType::from_primitive(u16::from_be_bytes([buffer[0], buffer[1]]));
183        let length = u16::from_be_bytes([buffer[2], buffer[3]]);
184
185        // Parse TLV content / value
186        if buffer.len() < 4 + length as usize {
187            return Err(Error::BufferTooShort);
188        }
189
190        let value = &buffer[4..][..length as usize];
191        Ok(Self {
192            tlv_type,
193            value: value.into(),
194        })
195    }
196
197    /// Ensure this TLV owns its storage.
198    #[cfg(feature = "std")]
199    #[must_use]
200    pub fn into_owned(self) -> Tlv<'static> {
201        Tlv {
202            tlv_type: self.tlv_type,
203            value: self.value.into_owned().into(),
204        }
205    }
206}
207
208/// The type of a given TLV.
209///
210/// For more detials, see *IEEE1588-2019 section 14.1.1 / Table 52*.
211#[derive(Debug, Clone, Copy, PartialEq, Eq)]
212#[repr(u8)]
213pub enum TlvType {
214    /// Reserved for future use
215    Reserved(u16),
216    /// The management TLV.
217    Management,
218    #[expect(clippy::doc_markdown)]
219    /// The ManagementErrorStatus TLV
220    ManagementErrorStatus,
221    /// An organization extension TLV.
222    ///
223    /// These have an additional set of identifiers identifying the actual type
224    /// in the TLV data itself.
225    OrganizationExtension,
226    /// A TLV containing a request for unicast transmission.
227    RequestUnicastTransmission,
228    /// A grant for unicast transmission.
229    GrantUnicastTransmission,
230    /// A request to cancel unicast transmission.
231    CancelUnicastTransmission,
232    /// Acknowledgement of unicast transmission cancelation.
233    AcknowledgeCancelUnicastTransmission,
234    /// Path tracing data.
235    PathTrace,
236    /// Information for computing a different timescale.
237    AlternateTimeOffsetIndicator,
238    /// TLV types used in previous versions of the standard.
239    Legacy(u16),
240    /// TLV identifiers inteded for experimentation.
241    Experimental(u16),
242    /// An organization extension TLV that needs to be propagated on announce messages.
243    ///
244    /// These have an additional set of identifiers identifying the actual type
245    /// in the TLV data itself.
246    OrganizationExtensionPropagate,
247    /// Enhanced accury metrics.
248    EnhancedAccuracyMetrics,
249    /// An organization extension TLV that must not be propagated on announce messages.
250    ///
251    /// These have an additional set of identifiers identifying the actual type
252    /// in the TLV data itself.
253    OrganizationExtensionDoNotPropagate,
254    /// Data for Layer 1 synchronization.
255    L1Sync,
256    /// Information about port communication capabilities.
257    PortCommunicationAvailability,
258    /// Protocol address of the sending PTP port
259    ProtocolAddress,
260    /// Timing data on received messages from time receiver monitoring.
261    SlaveRxSyncTimingData,
262    /// Computed data from time receiver monitoring.
263    SlaveRxSyncComputedData,
264    /// Timing data on sent message from time receiver monitoring.
265    SlaveTxEventTimestamps,
266    /// Cumulative frequency transfer data.
267    CumulativeRateRatio,
268    /// Padding.
269    Pad,
270    /// Message authentication.
271    Authentication,
272    /// CSPTP Status
273    CsptpStatus,
274    /// CSPTP Request
275    CsptpRequest,
276    /// CSPTP Response
277    CsptpResponse,
278}
279
280impl TlvType {
281    #[must_use]
282    pub(crate) fn to_primitive(self) -> u16 {
283        match self {
284            Self::Management => 0x0001,
285            Self::ManagementErrorStatus => 0x0002,
286            Self::OrganizationExtension => 0x0003,
287            Self::RequestUnicastTransmission => 0x0004,
288            Self::GrantUnicastTransmission => 0x0005,
289            Self::CancelUnicastTransmission => 0x0006,
290            Self::AcknowledgeCancelUnicastTransmission => 0x0007,
291            Self::PathTrace => 0x0008,
292            Self::AlternateTimeOffsetIndicator => 0x0009,
293            Self::OrganizationExtensionPropagate => 0x4000,
294            Self::EnhancedAccuracyMetrics => 0x4001,
295            Self::OrganizationExtensionDoNotPropagate => 0x8000,
296            Self::L1Sync => 0x8001,
297            Self::PortCommunicationAvailability => 0x8002,
298            Self::ProtocolAddress => 0x8003,
299            Self::SlaveRxSyncTimingData => 0x8004,
300            Self::SlaveRxSyncComputedData => 0x8005,
301            Self::SlaveTxEventTimestamps => 0x8006,
302            Self::CumulativeRateRatio => 0x8007,
303            Self::Pad => 0x8008,
304            Self::Authentication => 0x8009,
305            Self::CsptpRequest => 0xff00,
306            Self::CsptpResponse => 0xff01,
307            Self::CsptpStatus => 0xff02,
308            Self::Reserved(value) | Self::Legacy(value) | Self::Experimental(value) => value,
309        }
310    }
311
312    #[must_use]
313    pub(crate) fn from_primitive(value: u16) -> Self {
314        match value {
315            0x0000
316            | 0x000a..=0x1fff
317            | 0x2030..=0x3fff
318            | 0x4002..=0x7eff
319            | 0x800a..=0xfeff
320            | 0xff03..=0xffef
321            | 0xfff0..=0xffff => Self::Reserved(value),
322            0x2000..=0x2003 => Self::Legacy(value),
323            0x2004..=0x202f | 0x7f00..=0x7fff => Self::Experimental(value),
324            0x0001 => Self::Management,
325            0x0002 => Self::ManagementErrorStatus,
326            0x0003 => Self::OrganizationExtension,
327            0x0004 => Self::RequestUnicastTransmission,
328            0x0005 => Self::GrantUnicastTransmission,
329            0x0006 => Self::CancelUnicastTransmission,
330            0x0007 => Self::AcknowledgeCancelUnicastTransmission,
331            0x0008 => Self::PathTrace,
332            0x0009 => Self::AlternateTimeOffsetIndicator,
333            0x4000 => Self::OrganizationExtensionPropagate,
334            0x4001 => Self::EnhancedAccuracyMetrics,
335            0x8000 => Self::OrganizationExtensionDoNotPropagate,
336            0x8001 => Self::L1Sync,
337            0x8002 => Self::PortCommunicationAvailability,
338            0x8003 => Self::ProtocolAddress,
339            0x8004 => Self::SlaveRxSyncTimingData,
340            0x8005 => Self::SlaveRxSyncComputedData,
341            0x8006 => Self::SlaveTxEventTimestamps,
342            0x8007 => Self::CumulativeRateRatio,
343            0x8008 => Self::Pad,
344            0x8009 => Self::Authentication,
345            0xff00 => Self::CsptpRequest,
346            0xff01 => Self::CsptpResponse,
347            0xff02 => Self::CsptpStatus,
348        }
349    }
350
351    /// True if this message should be propagated by a boundary clock if it is
352    /// attached to an announce message
353    #[must_use]
354    pub fn announce_propagate(self) -> bool {
355        matches!(self.to_primitive(), 0x0008 | 0x0009 | 0x4000..=0x7fff)
356    }
357}
358
359#[cfg(test)]
360mod tests {
361    use super::*;
362
363    #[test]
364    fn serialize_management() {
365        let tlv = Tlv {
366            tlv_type: TlvType::Management,
367            value: (&b"hello!"[..]).into(),
368        };
369
370        let mut buffer = [0; 256];
371        tlv.serialize(&mut buffer).unwrap();
372
373        let n = tlv.wire_size();
374        assert_eq!(n, 10);
375
376        let decoded = Tlv::deserialize(&buffer[..n]).unwrap();
377
378        assert_eq!(tlv, decoded);
379    }
380
381    #[test]
382    fn parse_announce_propagate_messages() {
383        let mut alloc = [0; 256];
384        let mut buffer = &mut alloc[..];
385
386        let tlv1 = Tlv {
387            tlv_type: TlvType::Management,
388            value: (&b"hello!"[..]).into(),
389        };
390        tlv1.serialize(buffer).unwrap();
391        buffer = &mut buffer[tlv1.wire_size()..];
392        assert!(!tlv1.tlv_type.announce_propagate());
393
394        let tlv2 = Tlv {
395            tlv_type: TlvType::PathTrace,
396            value: (&b"PathTrace!"[..]).into(),
397        };
398        tlv2.serialize(buffer).unwrap();
399        buffer = &mut buffer[tlv2.wire_size()..];
400        assert!(tlv2.tlv_type.announce_propagate());
401
402        let tlv3 = Tlv {
403            tlv_type: TlvType::OrganizationExtensionPropagate,
404            value: (&b"OrganizationExtensionPropagate"[..]).into(),
405        };
406        tlv3.serialize(buffer).unwrap();
407        buffer = &mut buffer[tlv3.wire_size()..];
408        assert!(tlv3.tlv_type.announce_propagate());
409
410        let _ = buffer;
411
412        let buffer = &mut alloc[..tlv1.wire_size() + tlv2.wire_size() + tlv3.wire_size()];
413        let tlv_set = TlvSet::deserialize(buffer).unwrap();
414        let mut it = tlv_set.announce_propagate_tlvs();
415
416        assert_eq!(it.next(), Some(tlv2));
417        assert_eq!(it.next(), Some(tlv3));
418        assert_eq!(it.next(), None);
419    }
420
421    #[test]
422    fn parse_trailing_zero_length_tlv() {
423        let mut alloc = [0; 64];
424
425        let tlv1 = Tlv {
426            tlv_type: TlvType::PathTrace,
427            value: (&b"ab"[..]).into(),
428        };
429        let tlv2 = Tlv {
430            tlv_type: TlvType::Experimental(0x2004),
431            value: (&[][..]).into(),
432        };
433
434        tlv1.serialize(&mut alloc).unwrap();
435        tlv2.serialize(&mut alloc[tlv1.wire_size()..]).unwrap();
436
437        let buffer = &alloc[..tlv1.wire_size() + tlv2.wire_size()];
438        let tlv_set = TlvSet::deserialize(buffer).unwrap();
439
440        assert_eq!(tlv_set.wire_size(), buffer.len());
441
442        let mut it = tlv_set.tlvs();
443        assert_eq!(it.next(), Some(tlv1));
444        assert_eq!(it.next(), Some(tlv2));
445        assert_eq!(it.next(), None);
446    }
447
448    #[test]
449    fn parse_lone_zero_length_tlv() {
450        let tlv = Tlv {
451            tlv_type: TlvType::Experimental(0x2004),
452            value: (&[][..]).into(),
453        };
454
455        let mut alloc = [0; 64];
456        tlv.serialize(&mut alloc).unwrap();
457
458        let buffer = &alloc[..tlv.wire_size()];
459        let tlv_set = TlvSet::deserialize(buffer).unwrap();
460
461        assert_eq!(tlv_set.wire_size(), 4);
462
463        let mut it = tlv_set.tlvs();
464        assert_eq!(it.next(), Some(tlv));
465        assert_eq!(it.next(), None);
466    }
467
468    #[test]
469    fn iterate_built_set_ending_in_zero_length_tlv() {
470        let tlv1 = Tlv {
471            tlv_type: TlvType::PathTrace,
472            value: (&b"ab"[..]).into(),
473        };
474        let tlv2 = Tlv {
475            tlv_type: TlvType::Experimental(0x2004),
476            value: (&[][..]).into(),
477        };
478
479        let mut alloc = [0; 64];
480        let mut builder = TlvSetBuilder::new(&mut alloc);
481        builder.add(&tlv1).unwrap();
482        builder.add(&tlv2).unwrap();
483        let tlv_set = builder.build();
484
485        let mut it = tlv_set.tlvs();
486        assert_eq!(it.next(), Some(tlv1));
487        assert_eq!(it.next(), Some(tlv2));
488        assert_eq!(it.next(), None);
489    }
490}