File
Blob: firmware/vendor/sctp-proto/src/chunk/chunk_i_forward_tsn.rs
| 1 | use super::{chunk_forward_tsn::NEW_CUMULATIVE_TSN_LENGTH, chunk_header::*, chunk_type::*, *}; |
| 2 | use 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)] |
| 23 | pub(crate) struct ChunkIForwardTsn { |
| 24 | pub(crate) new_cumulative_tsn: u32, |
| 25 | pub(crate) streams: Vec<ChunkIForwardTsnStream>, |
| 26 | } |
| 27 | |
| 28 | const I_FORWARD_TSN_STREAM_ENTRY_LENGTH: usize = 8; |
| 29 | |
| 30 | impl 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 | |
| 44 | impl 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)] |
| 117 | pub(crate) struct ChunkIForwardTsnStream { |
| 118 | pub(crate) identifier: u16, |
| 119 | pub(crate) unordered: bool, |
| 120 | pub(crate) mid: u32, |
| 121 | } |