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