File
Blob: firmware/vendor/sctp-proto/src/chunk/chunk_header.rs
| 1 | use 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)] |
| 19 | pub(crate) struct ChunkHeader { |
| 20 | pub(crate) typ: ChunkType, |
| 21 | pub(crate) flags: u8, |
| 22 | pub(crate) value_length: u16, |
| 23 | } |
| 24 | |
| 25 | pub(crate) const CHUNK_HEADER_SIZE: usize = 4; |
| 26 | |
| 27 | /// makes ChunkHeader printable |
| 28 | impl fmt::Display for ChunkHeader { |
| 29 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 30 | write!(f, "{}", self.typ) |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | impl 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 | } |