1use crate::chunk::Chunk;
2
3use crate::chunk::chunk_abort::ChunkAbort;
4use crate::chunk::chunk_cookie_ack::ChunkCookieAck;
5use crate::chunk::chunk_cookie_echo::ChunkCookieEcho;
6use crate::chunk::chunk_error::ChunkError;
7use crate::chunk::chunk_forward_tsn::ChunkForwardTsn;
8use crate::chunk::chunk_header::*;
9use crate::chunk::chunk_heartbeat::ChunkHeartbeat;
10use crate::chunk::chunk_init::ChunkInit;
11use crate::chunk::chunk_payload_data::ChunkPayloadData;
12use crate::chunk::chunk_reconfig::ChunkReconfig;
13use crate::chunk::chunk_selective_ack::ChunkSelectiveAck;
14use crate::chunk::chunk_shutdown::ChunkShutdown;
15use crate::chunk::chunk_shutdown_ack::ChunkShutdownAck;
16use crate::chunk::chunk_shutdown_complete::ChunkShutdownComplete;
17use crate::chunk::chunk_type::*;
18use crate::error::{Error, Result};
19use crate::util::*;
20
21use bytes::{Buf, BufMut, Bytes, BytesMut};
22use crc::{Crc, CRC_32_ISCSI};
23use std::fmt;
24
25#[derive(Default, Debug)]
56pub(crate) struct Packet {
57 pub(crate) source_port: u16,
58 pub(crate) destination_port: u16,
59 pub(crate) verification_tag: u32,
60 pub(crate) chunks: Vec<Box<dyn Chunk + Send + Sync>>,
61}
62
63impl fmt::Display for Packet {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 let mut res = format!(
67 "Packet:
68 source_port: {}
69 destination_port: {}
70 verification_tag: {}
71 ",
72 self.source_port, self.destination_port, self.verification_tag,
73 );
74 for chunk in &self.chunks {
75 res += format!("Chunk: {}", chunk).as_str();
76 }
77 write!(f, "{}", res)
78 }
79}
80
81pub(crate) const PACKET_HEADER_SIZE: usize = 12;
82
83impl Packet {
84 pub(crate) fn unmarshal(raw: &Bytes) -> Result<Self> {
85 if raw.len() < PACKET_HEADER_SIZE {
86 return Err(Error::ErrPacketRawTooSmall);
87 }
88
89 let reader = &mut raw.clone();
90
91 let source_port = reader.get_u16();
92 let destination_port = reader.get_u16();
93 let verification_tag = reader.get_u32();
94 let their_checksum = reader.get_u32_le();
95 let our_checksum = generate_packet_checksum(raw);
96
97 if their_checksum != our_checksum {
98 return Err(Error::ErrChecksumMismatch);
99 }
100
101 let mut chunks = vec![];
102 let mut offset = PACKET_HEADER_SIZE;
103 loop {
104 if offset == raw.len() {
106 break;
107 } else if offset + CHUNK_HEADER_SIZE > raw.len() {
108 return Err(Error::ErrParseSctpChunkNotEnoughData);
109 }
110
111 let ct = ChunkType(raw[offset]);
112 let c: Box<dyn Chunk + Send + Sync> = match ct {
113 CT_INIT => Box::new(ChunkInit::unmarshal(&raw.slice(offset..))?),
114 CT_INIT_ACK => Box::new(ChunkInit::unmarshal(&raw.slice(offset..))?),
115 CT_ABORT => Box::new(ChunkAbort::unmarshal(&raw.slice(offset..))?),
116 CT_COOKIE_ECHO => Box::new(ChunkCookieEcho::unmarshal(&raw.slice(offset..))?),
117 CT_COOKIE_ACK => Box::new(ChunkCookieAck::unmarshal(&raw.slice(offset..))?),
118 CT_HEARTBEAT => Box::new(ChunkHeartbeat::unmarshal(&raw.slice(offset..))?),
119 CT_PAYLOAD_DATA => Box::new(ChunkPayloadData::unmarshal(&raw.slice(offset..))?),
120 CT_SACK => Box::new(ChunkSelectiveAck::unmarshal(&raw.slice(offset..))?),
121 CT_RECONFIG => Box::new(ChunkReconfig::unmarshal(&raw.slice(offset..))?),
122 CT_FORWARD_TSN => Box::new(ChunkForwardTsn::unmarshal(&raw.slice(offset..))?),
123 CT_ERROR => Box::new(ChunkError::unmarshal(&raw.slice(offset..))?),
124 CT_SHUTDOWN => Box::new(ChunkShutdown::unmarshal(&raw.slice(offset..))?),
125 CT_SHUTDOWN_ACK => Box::new(ChunkShutdownAck::unmarshal(&raw.slice(offset..))?),
126 CT_SHUTDOWN_COMPLETE => {
127 Box::new(ChunkShutdownComplete::unmarshal(&raw.slice(offset..))?)
128 }
129 _ => return Err(Error::ErrUnmarshalUnknownChunkType),
130 };
131
132 let chunk_value_padding = get_padding_size(c.value_length());
133 offset += CHUNK_HEADER_SIZE + c.value_length() + chunk_value_padding;
134 chunks.push(c);
135 }
136
137 Ok(Packet {
138 source_port,
139 destination_port,
140 verification_tag,
141 chunks,
142 })
143 }
144
145 pub(crate) fn marshal_to(&self, writer: &mut BytesMut) -> Result<usize> {
146 writer.put_u16(self.source_port);
149 writer.put_u16(self.destination_port);
150 writer.put_u32(self.verification_tag);
151
152 let mut raw = BytesMut::new();
154 for c in &self.chunks {
155 let chunk_raw = c.marshal()?;
156 raw.extend(chunk_raw);
157
158 let padding_needed = get_padding_size(raw.len());
159 if padding_needed != 0 {
160 raw.extend(vec![0u8; padding_needed]);
161 }
162 }
163 let raw = raw.freeze();
164
165 let hasher = Crc::<u32>::new(&CRC_32_ISCSI);
166 let mut digest = hasher.digest();
167 digest.update(&writer.to_vec());
168 digest.update(&FOUR_ZEROES);
169 digest.update(&raw[..]);
170 let checksum = digest.finalize();
171
172 writer.put_u32_le(checksum);
175 writer.extend(raw);
176
177 Ok(writer.len())
178 }
179
180 pub(crate) fn marshal(&self) -> Result<Bytes> {
181 let mut buf = BytesMut::with_capacity(PACKET_HEADER_SIZE);
182 self.marshal_to(&mut buf)?;
183 Ok(buf.freeze())
184 }
185}
186
187impl Packet {
188 pub(crate) fn check_packet(&self) -> Result<()> {
189 if self.source_port == 0 {
197 return Err(Error::ErrSctpPacketSourcePortZero);
198 }
199
200 if self.destination_port == 0 {
205 return Err(Error::ErrSctpPacketDestinationPortZero);
206 }
207
208 for c in &self.chunks {
210 if let Some(ci) = c.as_any().downcast_ref::<ChunkInit>() {
211 if !ci.is_ack {
212 if self.chunks.len() != 1 {
216 return Err(Error::ErrInitChunkBundled);
217 }
218
219 if self.verification_tag != 0 {
222 return Err(Error::ErrInitChunkVerifyTagNotZero);
223 }
224 }
225 }
226 }
227
228 Ok(())
229 }
230}
231
232#[cfg(test)]
233mod test {
234 use super::*;
235
236 #[test]
237 fn test_packet_unmarshal() -> Result<()> {
238 let result = Packet::unmarshal(&Bytes::new());
239 assert!(
240 result.is_err(),
241 "Unmarshal should fail when a packet is too small to be SCTP"
242 );
243
244 let header_only = Bytes::from_static(&[
245 0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x06, 0xa9, 0x00, 0xe1,
246 ]);
247 let pkt = Packet::unmarshal(&header_only)?;
248 assert_eq!(
250 pkt.source_port, 5000,
251 "Unmarshal passed for SCTP packet, but got incorrect source port exp: {} act: {}",
252 5000, pkt.source_port
253 );
254 assert_eq!(
255 pkt.destination_port, 5000,
256 "Unmarshal passed for SCTP packet, but got incorrect destination port exp: {} act: {}",
257 5000, pkt.destination_port
258 );
259 assert_eq!(
260 pkt.verification_tag, 0,
261 "Unmarshal passed for SCTP packet, but got incorrect verification tag exp: {} act: {}",
262 0, pkt.verification_tag
263 );
264
265 let raw_chunk = Bytes::from_static(&[
266 0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x81, 0x46, 0x9d, 0xfc, 0x01, 0x00,
267 0x00, 0x56, 0x55, 0xb9, 0x64, 0xa5, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
268 0xe8, 0x6d, 0x10, 0x30, 0xc0, 0x00, 0x00, 0x04, 0x80, 0x08, 0x00, 0x09, 0xc0, 0x0f,
269 0xc1, 0x80, 0x82, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x24, 0x9f, 0xeb, 0xbb, 0x5c,
270 0x50, 0xc9, 0xbf, 0x75, 0x9c, 0xb1, 0x2c, 0x57, 0x4f, 0xa4, 0x5a, 0x51, 0xba, 0x60,
271 0x17, 0x78, 0x27, 0x94, 0x5c, 0x31, 0xe6, 0x5d, 0x5b, 0x09, 0x47, 0xe2, 0x22, 0x06,
272 0x80, 0x04, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x06, 0x80, 0xc1,
273 0x00, 0x00,
274 ]);
275
276 Packet::unmarshal(&raw_chunk)?;
277
278 Ok(())
279 }
280
281 #[test]
282 fn test_packet_marshal() -> Result<()> {
283 let header_only = Bytes::from_static(&[
284 0x13, 0x88, 0x13, 0x88, 0x00, 0x00, 0x00, 0x00, 0x06, 0xa9, 0x00, 0xe1,
285 ]);
286 let pkt = Packet::unmarshal(&header_only)?;
287 let header_only_marshaled = pkt.marshal()?;
288 assert_eq!(header_only, header_only_marshaled, "Unmarshal/Marshaled header only packet did not match \nheaderOnly: {:?} \nheader_only_marshaled {:?}", header_only, header_only_marshaled);
289
290 Ok(())
291 }
292
293 }