Skip to content
File

Blob: firmware/vendor/sctp-proto/src/chunk/chunk_i_forward_tsn.rs

rust122 lines
1use super::{chunk_forward_tsn::NEW_CUMULATIVE_TSN_LENGTH, chunk_header::*, chunk_type::*, *};
2use alloc::string::ToString;
3 
4/// I-FORWARD-TSN chunk (RFC 8260).
5///
6/// Identical purpose to FORWARD-TSN (RFC 3758) but carries per-stream
7/// entries with a 32-bit Message Identifier (MID) instead of a 16-bit SSN,
8/// and an explicit unordered flag per entry.
9///
10/// 0 1 2 3
11/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
12///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13///| Type = 194 | Flags = 0x00 | Length = Variable |
14///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15///| New Cumulative TSN |
16///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17///| Stream Identifier | Flags | Reserved |
18///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19///| Message Identifier (MID) |
20///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21/// ...
22#[derive(Default, Debug, Clone)]
23pub(crate) struct ChunkIForwardTsn {
24 pub(crate) new_cumulative_tsn: u32,
25 pub(crate) streams: Vec<ChunkIForwardTsnStream>,
26}
27 
28const I_FORWARD_TSN_STREAM_ENTRY_LENGTH: usize = 8;
29 
30impl fmt::Display for ChunkIForwardTsn {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 let mut res = vec![self.header().to_string()];
33 res.push(format!("New Cumulative TSN: {}", self.new_cumulative_tsn));
34 for s in &self.streams {
35 res.push(format!(
36 " - si={}, unordered={}, mid={}",
37 s.identifier, s.unordered, s.mid
38 ));
39 }
40 write!(f, "{}", res.join("\n"))
41 }
42}
43 
44impl Chunk for ChunkIForwardTsn {
45 fn header(&self) -> ChunkHeader {
46 ChunkHeader {
47 typ: CT_I_FORWARD_TSN,
48 flags: 0,
49 value_length: self.value_length() as u16,
50 }
51 }
52 
53 fn unmarshal(buf: &Bytes) -> Result<Self> {
54 let header = ChunkHeader::unmarshal(buf)?;
55 
56 if header.typ != CT_I_FORWARD_TSN {
57 return Err(Error::ErrChunkTypeNotForwardTsn);
58 }
59 
60 let value_end = CHUNK_HEADER_SIZE + header.value_length();
61 if header.value_length() < NEW_CUMULATIVE_TSN_LENGTH {
62 return Err(Error::ErrChunkTooShort);
63 }
64 
65 let reader = &mut buf.slice(CHUNK_HEADER_SIZE..value_end);
66 let new_cumulative_tsn = reader.get_u32();
67 
68 let mut streams = vec![];
69 let mut offset = CHUNK_HEADER_SIZE + NEW_CUMULATIVE_TSN_LENGTH;
70 while offset + I_FORWARD_TSN_STREAM_ENTRY_LENGTH <= value_end {
71 let entry_buf = &mut buf.slice(offset..value_end);
72 let identifier = entry_buf.get_u16();
73 let flags = entry_buf.get_u8();
74 let _reserved = entry_buf.get_u8();
75 let mid = entry_buf.get_u32();
76 
77 streams.push(ChunkIForwardTsnStream {
78 identifier,
79 unordered: (flags & 0x01) != 0,
80 mid,
81 });
82 offset += I_FORWARD_TSN_STREAM_ENTRY_LENGTH;
83 }
84 
85 Ok(ChunkIForwardTsn {
86 new_cumulative_tsn,
87 streams,
88 })
89 }
90 
91 fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
92 self.header().marshal_to(writer)?;
93 writer.put_u32(self.new_cumulative_tsn);
94 for s in &self.streams {
95 writer.put_u16(s.identifier);
96 writer.put_u8(if s.unordered { 0x01 } else { 0x00 });
97 writer.put_u8(0); // reserved
98 writer.put_u32(s.mid);
99 }
100 Ok(writer.len())
101 }
102 
103 fn check(&self) -> Result<()> {
104 Ok(())
105 }
106 
107 fn value_length(&self) -> usize {
108 4 + I_FORWARD_TSN_STREAM_ENTRY_LENGTH * self.streams.len()
109 }
110 
111 fn as_any(&self) -> &(dyn Any + Send + Sync) {
112 self
113 }
114}
115 
116#[derive(Debug, Clone)]
117pub(crate) struct ChunkIForwardTsnStream {
118 pub(crate) identifier: u16,
119 pub(crate) unordered: bool,
120 pub(crate) mid: u32,
121}