cat_dev/fsemul/pcfs/sata_proto/
ping.rs1use crate::{
8 errors::NetworkParseError,
9 fsemul::pcfs::{
10 errors::PCFSApiError,
11 sata_proto::{construct_sata_response, SataCommandInfo, SataPacketHeader},
12 },
13};
14use bytes::{BufMut, Bytes, BytesMut};
15use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
16
17#[derive(Clone, Debug, PartialEq, Eq, Valuable)]
19pub struct SataPingPacketBody;
20
21impl SataPingPacketBody {
22 pub fn handle(
29 &self,
30 request_header: &SataPacketHeader,
31 command_info: &SataCommandInfo,
32 server_and_client_supports_ffio: bool,
33 server_and_client_supports_csr: bool,
34 ) -> Result<Bytes, PCFSApiError> {
35 let supports_ffio = command_info.capabilities.0 != 0 && server_and_client_supports_ffio;
36 let supports_csr = command_info.capabilities.0 != 0 && server_and_client_supports_csr;
37
38 construct_sata_response(
39 request_header,
40 0,
41 SataPongBody::new(supports_ffio, supports_csr),
42 )
43 }
44}
45
46impl TryFrom<Bytes> for SataPingPacketBody {
47 type Error = NetworkParseError;
48
49 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
50 if !value.is_empty() {
51 return Err(NetworkParseError::UnexpectedTrailer(
52 "SataPingPacketBody",
53 value,
54 ));
55 }
56
57 Ok(Self)
58 }
59}
60
61#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct SataPongBody {
64 fast_file_io_enabled: bool,
66 combined_send_recv_enabled: bool,
68}
69
70impl SataPongBody {
71 #[must_use]
72 pub const fn new(ffio_enabled: bool, csr_enabled: bool) -> Self {
73 Self {
74 fast_file_io_enabled: ffio_enabled,
75 combined_send_recv_enabled: csr_enabled,
76 }
77 }
78
79 #[must_use]
80 pub const fn ffio_enabled(&self) -> bool {
81 self.fast_file_io_enabled
82 }
83
84 pub const fn set_ffio_enabled(&mut self, enabled: bool) {
85 self.fast_file_io_enabled = enabled;
86 }
87
88 #[must_use]
89 pub const fn combined_send_recv_enabled(&self) -> bool {
90 self.combined_send_recv_enabled
91 }
92
93 pub const fn set_combined_send_recv_enabled(&mut self, enabled: bool) {
94 self.combined_send_recv_enabled = enabled;
95 }
96}
97
98impl From<SataPongBody> for Bytes {
99 fn from(value: SataPongBody) -> Self {
100 let mut buff = BytesMut::with_capacity(8);
101
102 buff.put_u32(0x0); buff.put_u32(
104 match (value.fast_file_io_enabled, value.combined_send_recv_enabled) {
105 (true, true) => 0xCAFE_0003,
106 (true, false) => 0xCAFE_0001,
107 (false, true) => 0xCAFE_0002,
108 (false, false) => 0x0000_0000,
109 },
110 );
111
112 buff.freeze()
113 }
114}
115
116const SATA_PONG_BODY_FIELDS: &[NamedField<'static>] = &[
117 NamedField::new("fast_file_io_enabled"),
118 NamedField::new("combined_send_recv_enabled"),
119];
120
121impl Structable for SataPongBody {
122 fn definition(&self) -> StructDef<'_> {
123 StructDef::new_static("SataPongBody", Fields::Named(SATA_PONG_BODY_FIELDS))
124 }
125}
126
127impl Valuable for SataPongBody {
128 fn as_value(&self) -> Value<'_> {
129 Value::Structable(self)
130 }
131
132 fn visit(&self, visitor: &mut dyn Visit) {
133 visitor.visit_named_fields(&NamedValues::new(
134 SATA_PONG_BODY_FIELDS,
135 &[
136 Valuable::as_value(&self.fast_file_io_enabled),
137 Valuable::as_value(&self.combined_send_recv_enabled),
138 ],
139 ));
140 }
141}
142
143#[cfg(test)]
144mod unit_tests {
145 use super::*;
146
147 #[test]
148 pub fn can_respond_to_ping() {
149 let ping = SataPingPacketBody;
150
151 let example_ping_packet_header = SataPacketHeader {
152 packet_data_len: 0,
153 packet_id: 0,
154 flags: 0,
155 version: 0,
156 timestamp_on_host: 0,
157 pid_on_host: 0,
158 };
159 let example_command_info = SataCommandInfo {
160 user: (0, 0),
161 capabilities: (1, 0),
162 command: 0x14,
163 };
164
165 let all_supported = ping
166 .handle(
167 &example_ping_packet_header,
168 &example_command_info,
169 true,
170 true,
171 )
172 .expect("Failed to handle ping with all features enabled!");
173 let only_ffio_supported = ping
174 .handle(
175 &example_ping_packet_header,
176 &example_command_info,
177 true,
178 false,
179 )
180 .expect("Failed to handle ping with only ffio features enabled!");
181 let only_csr_supported = ping
182 .handle(
183 &example_ping_packet_header,
184 &example_command_info,
185 false,
186 true,
187 )
188 .expect("Failed to handle ping with only csr enabled!");
189 let none_supported = ping
190 .handle(
191 &example_ping_packet_header,
192 &example_command_info,
193 false,
194 false,
195 )
196 .expect("Failed to handle ping with only csr enabled!");
197
198 assert!(all_supported.ends_with(&[0xCA, 0xFE, 0x00, 0x03]));
199 assert!(only_ffio_supported.ends_with(&[0xCA, 0xFE, 0x00, 0x01]));
200 assert!(only_csr_supported.ends_with(&[0xCA, 0xFE, 0x00, 0x02]));
201 assert!(none_supported.ends_with(&[0x00, 0x00, 0x00, 0x00]));
202 }
203}