Skip to content
File

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

rust103 lines
1use super::{chunk_type::*, *};
2 
3///chunkHeader represents a SCTP Chunk header, defined in https://tools.ietf.org/html/rfc4960#section-3.2
4///The figure below illustrates the field format for the chunks to be
5///transmitted in the SCTP packet. Each chunk is formatted with a Chunk
6///Type field, a chunk-specific Flag field, a Chunk Length field, and a
7///Value field.
8///
9/// 0 1 2 3
10/// 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
11///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12///| Chunk Type | Chunk Flags | Chunk Length |
13///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14///| |
15///| Chunk Value |
16///| |
17///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18#[derive(Default, Debug, Clone)]
19pub(crate) struct ChunkHeader {
20 pub(crate) typ: ChunkType,
21 pub(crate) flags: u8,
22 pub(crate) value_length: u16,
23}
24 
25pub(crate) const CHUNK_HEADER_SIZE: usize = 4;
26 
27/// makes ChunkHeader printable
28impl fmt::Display for ChunkHeader {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 write!(f, "{}", self.typ)
31 }
32}
33 
34impl Chunk for ChunkHeader {
35 fn header(&self) -> ChunkHeader {
36 self.clone()
37 }
38 
39 fn unmarshal(raw: &Bytes) -> Result<Self> {
40 if raw.len() < CHUNK_HEADER_SIZE {
41 return Err(Error::ErrChunkHeaderTooSmall);
42 }
43 
44 let reader = &mut raw.clone();
45 
46 let typ = ChunkType(reader.get_u8());
47 let flags = reader.get_u8();
48 let length = reader.get_u16();
49 
50 if length < CHUNK_HEADER_SIZE as u16 {
51 return Err(Error::ErrChunkHeaderInvalidLength);
52 }
53 
54 // Length includes Chunk header
55 let value_length = length as isize - CHUNK_HEADER_SIZE as isize;
56 let length_after_value = raw.len() as isize - length as isize;
57 if length_after_value < 0 {
58 return Err(Error::ErrChunkHeaderNotEnoughSpace);
59 } else if length_after_value < 4 {
60 // https://tools.ietf.org/html/rfc4960#section-3.2
61 // The Chunk Length field does not count any chunk PADDING.
62 // Chunks (including Type, Length, and Value fields) are padded out
63 // by the sender with all zero bytes to be a multiple of 4 bytes
64 // long. This PADDING MUST NOT be more than 3 bytes in total. The
65 // Chunk Length value does not include terminating PADDING of the
66 // chunk. However, it does include PADDING of any variable-length
67 // parameter except the last parameter in the chunk. The receiver
68 // MUST ignore the PADDING.
69 for i in (1..=length_after_value).rev() {
70 let padding_offset = CHUNK_HEADER_SIZE + (value_length + i - 1) as usize;
71 if raw[padding_offset] != 0 {
72 return Err(Error::ErrChunkHeaderPaddingNonZero);
73 }
74 }
75 }
76 
77 Ok(ChunkHeader {
78 typ,
79 flags,
80 value_length: length - CHUNK_HEADER_SIZE as u16,
81 })
82 }
83 
84 fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
85 writer.put_u8(self.typ.0);
86 writer.put_u8(self.flags);
87 writer.put_u16(self.value_length + CHUNK_HEADER_SIZE as u16);
88 Ok(writer.len())
89 }
90 
91 fn check(&self) -> Result<()> {
92 Ok(())
93 }
94 
95 fn value_length(&self) -> usize {
96 self.value_length as usize
97 }
98 
99 fn as_any(&self) -> &(dyn Any + Send + Sync) {
100 self
101 }
102}