virtio_accel_device/
frame.rs1use virtio_accel_core::{ByteSink, ByteSource};
9use virtio_accel_proto::StatusCode;
10
11use crate::{
12 ChainLayoutError, ChainRegion, DecodedRequest, FrameDecodeError, FrameDecoder,
13 ResponseWriteError, ResponseWriter, UnrecoverableDecodeError, validate_chain_layout,
14};
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum UnusableFrame {
18 ChainLayout(ChainLayoutError),
19 Request(UnrecoverableDecodeError),
20 InsufficientResponse {
21 request_id: u64,
22 required: u64,
23 available: u64,
24 },
25}
26
27#[derive(Debug)]
28pub enum FramePreflight<'a> {
29 Ready(DecodedRequest<'a>),
31 Rejected {
33 request_id: u64,
34 status: StatusCode,
35 used: u32,
36 },
37 Unusable(UnusableFrame),
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub enum FramePreflightError {
43 ResponseWrite(ResponseWriteError),
44}
45
46pub fn preflight_command_frame<'a>(
52 decoder: &FrameDecoder,
53 regions: &[ChainRegion],
54 request: &'a dyn ByteSource,
55 response: &mut dyn ByteSink,
56) -> Result<FramePreflight<'a>, FramePreflightError> {
57 let layout = match validate_chain_layout(regions, decoder.limits().max_chain_descriptors()) {
58 Ok(layout) => layout,
59 Err(error) => {
60 return Ok(FramePreflight::Unusable(UnusableFrame::ChainLayout(error)));
61 }
62 };
63 if let Err(error) = layout.validate_port_lengths(request.len(), response.len()) {
64 return Ok(FramePreflight::Unusable(UnusableFrame::ChainLayout(error)));
65 }
66
67 match decoder.decode(request, response.len()) {
68 Ok(request) => Ok(FramePreflight::Ready(request)),
69 Err(FrameDecodeError::Protocol { request_id, status }) => {
70 let used = ResponseWriter::new(response, decoder.limits().max_response_bytes())
71 .write_empty(status, request_id)
72 .map_err(FramePreflightError::ResponseWrite)?;
73 Ok(FramePreflight::Rejected {
74 request_id,
75 status,
76 used,
77 })
78 }
79 Err(FrameDecodeError::Unrecoverable(error)) => {
80 Ok(FramePreflight::Unusable(UnusableFrame::Request(error)))
81 }
82 Err(FrameDecodeError::InsufficientResponse {
83 request_id,
84 required,
85 available,
86 }) => Ok(FramePreflight::Unusable(
87 UnusableFrame::InsufficientResponse {
88 request_id,
89 required,
90 available,
91 },
92 )),
93 }
94}