Skip to content
File

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

rust123 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///chunkHeartbeatAck represents an SCTP Chunk of type HEARTBEAT ACK
7///
8///An endpoint should send this chunk to its peer endpoint as a response
9///to a HEARTBEAT chunk (see Section 8.3). A HEARTBEAT ACK is always
10///sent to the source IP address of the IP datagram containing the
11///HEARTBEAT chunk to which this ack is responding.
12///
13///The parameter field contains a variable-length opaque data structure.
14///
15/// 0 1 2 3
16/// 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
17///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18///| Type = 5 | Chunk Flags | Heartbeat Ack Length |
19///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20///| |
21///| Heartbeat Information TLV (Variable-Length) |
22///| |
23///+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24///
25///
26///Defined as a variable-length parameter using the format described
27///in Section 3.2.1, i.e.:
28///
29///Variable Parameters Status Type Value
30///-------------------------------------------------------------
31///Heartbeat Info Mandatory 1
32#[derive(Default, Debug)]
33pub(crate) struct ChunkHeartbeatAck {
34 pub(crate) params: Vec<Box<dyn Param + Send + Sync>>,
35}
36 
37/// makes ChunkHeartbeatAck printable
38impl fmt::Display for ChunkHeartbeatAck {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "{}", self.header())
41 }
42}
43 
44impl Chunk for ChunkHeartbeatAck {
45 fn header(&self) -> ChunkHeader {
46 ChunkHeader {
47 typ: CT_HEARTBEAT_ACK,
48 flags: 0,
49 value_length: self.value_length() as u16,
50 }
51 }
52 
53 fn unmarshal(raw: &Bytes) -> Result<Self> {
54 let header = ChunkHeader::unmarshal(raw)?;
55 
56 if header.typ != CT_HEARTBEAT_ACK {
57 return Err(Error::ErrChunkTypeNotHeartbeatAck);
58 }
59 
60 if header.value_length() < PARAM_HEADER_LENGTH {
61 return Err(Error::ErrHeartbeatNotLongEnoughInfo);
62 }
63 
64 let p =
65 build_param(&raw.slice(CHUNK_HEADER_SIZE..CHUNK_HEADER_SIZE + header.value_length()))?;
66 if p.header().typ != ParamType::HeartbeatInfo {
67 return Err(Error::ErrHeartbeatParam);
68 }
69 let params = vec![p];
70 
71 Ok(ChunkHeartbeatAck { params })
72 }
73 
74 fn marshal_to(&self, buf: &mut BytesMut) -> Result<usize> {
75 if self.params.len() != 1 {
76 return Err(Error::ErrHeartbeatAckParams);
77 }
78 if self.params[0].header().typ != ParamType::HeartbeatInfo {
79 return Err(Error::ErrHeartbeatAckNotHeartbeatInfo);
80 }
81 
82 self.header().marshal_to(buf)?;
83 for (idx, p) in self.params.iter().enumerate() {
84 let pp = p.marshal()?;
85 let pp_len = pp.len();
86 buf.extend(pp);
87 
88 // Chunks (including Type, Length, and Value fields) are padded out
89 // by the sender with all zero bytes to be a multiple of 4 bytes
90 // long. This PADDING MUST NOT be more than 3 bytes in total. The
91 // Chunk Length value does not include terminating PADDING of the
92 // chunk. *However, it does include PADDING of any variable-length
93 // parameter except the last parameter in the chunk.* The receiver
94 // MUST ignore the PADDING.
95 if idx != self.params.len() - 1 {
96 let cnt = get_padding_size(pp_len);
97 buf.extend(vec![0u8; cnt]);
98 }
99 }
100 Ok(buf.len())
101 }
102 
103 fn check(&self) -> Result<()> {
104 Ok(())
105 }
106 
107 fn value_length(&self) -> usize {
108 let mut l = 0;
109 for (idx, p) in self.params.iter().enumerate() {
110 let p_len = PARAM_HEADER_LENGTH + p.value_length();
111 l += p_len;
112 if idx != self.params.len() - 1 {
113 l += get_padding_size(p_len);
114 }
115 }
116 l
117 }
118 
119 fn as_any(&self) -> &(dyn Any + Send + Sync) {
120 self
121 }
122}