Skip to content
File

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

rust159 lines
1use super::{chunk_header::*, chunk_type::*, *};
2 
3///chunkSelectiveAck represents an SCTP Chunk of type SACK
4///
5///This chunk is sent to the peer endpoint to acknowledge received DATA
6///chunks and to inform the peer endpoint of gaps in the received
7///subsequences of DATA chunks as represented by their TSNs.
8///0 1 2 3
9///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
10///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11///| Type = 3 |Chunk Flags | Chunk Length |
12///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13///| Cumulative TSN Ack |
14///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15///| Advertised Receiver Window Credit (a_rwnd) |
16///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17///| Number of Gap Ack Blocks = N | Number of Duplicate TSNs = X |
18///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19///| Gap Ack Block #1 Start | Gap Ack Block #1 End |
20///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21///| |
22///| ... |
23///| |
24///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25///| Gap Ack Block #N Start | Gap Ack Block #N End |
26///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27///| Duplicate TSN 1 |
28///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29///| |
30///| ... |
31///| |
32///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33///| Duplicate TSN X |
34///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35#[derive(Debug, Default, Copy, Clone)]
36pub(crate) struct GapAckBlock {
37 pub(crate) start: u16,
38 pub(crate) end: u16,
39}
40 
41/// makes gapAckBlock printable
42impl fmt::Display for GapAckBlock {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 write!(f, "{} - {}", self.start, self.end)
45 }
46}
47 
48#[derive(Default, Debug)]
49pub(crate) struct ChunkSelectiveAck {
50 pub(crate) cumulative_tsn_ack: u32,
51 pub(crate) advertised_receiver_window_credit: u32,
52 pub(crate) gap_ack_blocks: Vec<GapAckBlock>,
53 pub(crate) duplicate_tsn: Vec<u32>,
54}
55 
56/// makes chunkSelectiveAck printable
57impl fmt::Display for ChunkSelectiveAck {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 let mut res = format!(
60 "SACK cumTsnAck={} arwnd={} dupTsn={:?}",
61 self.cumulative_tsn_ack, self.advertised_receiver_window_credit, self.duplicate_tsn
62 );
63 
64 for gap in &self.gap_ack_blocks {
65 res += format!("\n gap ack: {}", gap).as_str();
66 }
67 
68 write!(f, "{}", res)
69 }
70}
71 
72pub(crate) const SELECTIVE_ACK_HEADER_SIZE: usize = 12;
73 
74impl Chunk for ChunkSelectiveAck {
75 fn header(&self) -> ChunkHeader {
76 ChunkHeader {
77 typ: CT_SACK,
78 flags: 0,
79 value_length: self.value_length() as u16,
80 }
81 }
82 
83 fn unmarshal(raw: &Bytes) -> Result<Self> {
84 let header = ChunkHeader::unmarshal(raw)?;
85 
86 if header.typ != CT_SACK {
87 return Err(Error::ErrChunkTypeNotSack);
88 }
89 
90 if header.value_length() < SELECTIVE_ACK_HEADER_SIZE {
91 return Err(Error::ErrSackSizeNotLargeEnoughInfo);
92 }
93 
94 let reader = &mut raw.slice(CHUNK_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length());
95 
96 let cumulative_tsn_ack = reader.get_u32();
97 let advertised_receiver_window_credit = reader.get_u32();
98 let gap_ack_blocks_len = reader.get_u16() as usize;
99 let duplicate_tsn_len = reader.get_u16() as usize;
100 
101 // The reader is bounded by header.value_length(), so we
102 // must check against that, not raw.len() which may include
103 // subsequent chunks.
104 if header.value_length()
105 < SELECTIVE_ACK_HEADER_SIZE + (4 * gap_ack_blocks_len + 4 * duplicate_tsn_len)
106 {
107 return Err(Error::ErrSackSizeNotLargeEnoughInfo);
108 }
109 
110 let mut gap_ack_blocks = vec![];
111 let mut duplicate_tsn = vec![];
112 for _ in 0..gap_ack_blocks_len {
113 let start = reader.get_u16();
114 let end = reader.get_u16();
115 gap_ack_blocks.push(GapAckBlock { start, end });
116 }
117 for _ in 0..duplicate_tsn_len {
118 duplicate_tsn.push(reader.get_u32());
119 }
120 
121 Ok(ChunkSelectiveAck {
122 cumulative_tsn_ack,
123 advertised_receiver_window_credit,
124 gap_ack_blocks,
125 duplicate_tsn,
126 })
127 }
128 
129 fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
130 self.header().marshal_to(writer)?;
131 
132 writer.put_u32(self.cumulative_tsn_ack);
133 writer.put_u32(self.advertised_receiver_window_credit);
134 writer.put_u16(self.gap_ack_blocks.len() as u16);
135 writer.put_u16(self.duplicate_tsn.len() as u16);
136 for g in &self.gap_ack_blocks {
137 writer.put_u16(g.start);
138 writer.put_u16(g.end);
139 }
140 for t in &self.duplicate_tsn {
141 writer.put_u32(*t);
142 }
143 
144 Ok(writer.len())
145 }
146 
147 fn check(&self) -> Result<()> {
148 Ok(())
149 }
150 
151 fn value_length(&self) -> usize {
152 SELECTIVE_ACK_HEADER_SIZE + self.gap_ack_blocks.len() * 4 + self.duplicate_tsn.len() * 4
153 }
154 
155 fn as_any(&self) -> &(dyn Any + Send + Sync) {
156 self
157 }
158}