1use core::iter::FusedIterator;
2
3use crate::Error;
4
5#[derive(PartialEq, Eq)]
7pub struct TlvSetBuilder<'a> {
8 buffer: &'a mut [u8],
9 used: usize,
10}
11
12impl<'a> TlvSetBuilder<'a> {
13 pub fn new(buffer: &'a mut [u8]) -> Self {
15 Self { buffer, used: 0 }
16 }
17
18 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 #[must_use]
31 pub fn build(self) -> TlvSet<'a> {
32 TlvSet {
33 bytes: &self.buffer[..self.used],
34 }
35 }
36}
37
38#[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 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 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 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 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#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct Tlv<'a> {
136 pub tlv_type: TlvType,
138 #[cfg(not(feature = "std"))]
143 pub value: &'a [u8],
144 #[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 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 #[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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
212#[repr(u8)]
213pub enum TlvType {
214 Reserved(u16),
216 Management,
218 #[expect(clippy::doc_markdown)]
219 ManagementErrorStatus,
221 OrganizationExtension,
226 RequestUnicastTransmission,
228 GrantUnicastTransmission,
230 CancelUnicastTransmission,
232 AcknowledgeCancelUnicastTransmission,
234 PathTrace,
236 AlternateTimeOffsetIndicator,
238 Legacy(u16),
240 Experimental(u16),
242 OrganizationExtensionPropagate,
247 EnhancedAccuracyMetrics,
249 OrganizationExtensionDoNotPropagate,
254 L1Sync,
256 PortCommunicationAvailability,
258 ProtocolAddress,
260 SlaveRxSyncTimingData,
262 SlaveRxSyncComputedData,
264 SlaveTxEventTimestamps,
266 CumulativeRateRatio,
268 Pad,
270 Authentication,
272 CsptpStatus,
274 CsptpRequest,
276 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 #[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}