Skip to content
File

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

rust151 lines
1use super::{chunk_header::*, chunk_type::*, *};
2use crate::param::param_type::ParamType;
3use crate::param::{param_header::*, *};
4use crate::util::get_padding_size;
5 
6///https://tools.ietf.org/html/rfc6525#section-3.1
7///chunkReconfig represents an SCTP Chunk used to reconfigure streams.
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///| Type = 130 | Chunk Flags | Chunk Length |
13///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14///| |
15///| Re-configuration Parameter |
16///| |
17///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18///| |
19///| Re-configuration Parameter (optional) |
20///| |
21///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22#[derive(Default, Debug)]
23pub(crate) struct ChunkReconfig {
24 pub(crate) param_a: Option<Box<dyn Param + Send + Sync>>,
25 pub(crate) param_b: Option<Box<dyn Param + Send + Sync>>,
26}
27 
28impl Clone for ChunkReconfig {
29 fn clone(&self) -> Self {
30 ChunkReconfig {
31 param_a: self.param_a.as_ref().cloned(),
32 param_b: self.param_b.as_ref().cloned(),
33 }
34 }
35}
36 
37/// makes chunkReconfig printable
38impl fmt::Display for ChunkReconfig {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 let mut res = String::new();
41 if let Some(param_a) = &self.param_a {
42 res += format!("Param A:\n {}", param_a).as_str();
43 }
44 if let Some(param_b) = &self.param_b {
45 res += format!("Param B:\n {}", param_b).as_str()
46 }
47 write!(f, "{}", res)
48 }
49}
50 
51impl Chunk for ChunkReconfig {
52 fn header(&self) -> ChunkHeader {
53 ChunkHeader {
54 typ: CT_RECONFIG,
55 flags: 0,
56 value_length: self.value_length() as u16,
57 }
58 }
59 
60 fn unmarshal(raw: &Bytes) -> Result<Self> {
61 let header = ChunkHeader::unmarshal(raw)?;
62 
63 if header.typ != CT_RECONFIG {
64 return Err(Error::ErrChunkTypeNotReconfig);
65 }
66 
67 if header.value_length() < PARAM_HEADER_LENGTH {
68 return Err(Error::ErrChunkTooShort);
69 }
70 
71 let param_a =
72 build_param(&raw.slice(CHUNK_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length()))?;
73 
74 let padding = get_padding_size(PARAM_HEADER_LENGTH + param_a.value_length());
75 let offset = CHUNK_HEADER_SIZE + PARAM_HEADER_LENGTH + param_a.value_length() + padding;
76 let param_b = if CHUNK_HEADER_SIZE + header.value_length() > offset {
77 Some(build_param(
78 &raw.slice(offset..CHUNK_HEADER_SIZE + header.value_length()),
79 )?)
80 } else {
81 None
82 };
83 
84 Ok(ChunkReconfig {
85 param_a: Some(param_a),
86 param_b,
87 })
88 }
89 
90 fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
91 self.header().marshal_to(writer)?;
92 
93 let param_a_value_length = if let Some(param_a) = &self.param_a {
94 writer.extend(param_a.marshal()?);
95 param_a.value_length()
96 } else {
97 return Err(Error::ErrChunkReconfigInvalidParamA);
98 };
99 
100 if let Some(param_b) = &self.param_b {
101 // Pad param A
102 let padding = get_padding_size(PARAM_HEADER_LENGTH + param_a_value_length);
103 writer.extend(vec![0u8; padding]);
104 writer.extend(param_b.marshal()?);
105 }
106 Ok(writer.len())
107 }
108 
109 fn check(&self) -> Result<()> {
110 let param_a = self
111 .param_a
112 .as_ref()
113 .ok_or(Error::ErrChunkReconfigInvalidParamA)?;
114 let Some(param_b) = &self.param_b else {
115 return Ok(());
116 };
117 
118 let combination = (param_a.header().typ, param_b.header().typ);
119 if matches!(
120 combination,
121 (ParamType::OutSsnResetReq, ParamType::IncSsnResetReq)
122 | (ParamType::AddOutStreamsReq, ParamType::AddIncStreamsReq)
123 | (ParamType::ReconfigResp, ParamType::OutSsnResetReq)
124 | (ParamType::ReconfigResp, ParamType::ReconfigResp)
125 ) {
126 Ok(())
127 } else {
128 Err(Error::ErrChunkReconfigInvalidParamCombination)
129 }
130 }
131 
132 fn value_length(&self) -> usize {
133 let mut l = PARAM_HEADER_LENGTH;
134 let param_a_value_length = if let Some(param_a) = &self.param_a {
135 l += param_a.value_length();
136 param_a.value_length()
137 } else {
138 0
139 };
140 if let Some(param_b) = &self.param_b {
141 let padding = get_padding_size(PARAM_HEADER_LENGTH + param_a_value_length);
142 l += PARAM_HEADER_LENGTH + param_b.value_length() + padding;
143 }
144 l
145 }
146 
147 fn as_any(&self) -> &(dyn Any + Send + Sync) {
148 self
149 }
150}