blob: 331166860c1f5498bc65ea6ed1d1c13f5200dc71 [file]
// Licensed under the Apache-2.0 license
// SPDX-License-Identifier: Apache-2.0
//! Shared in-memory MCTP test plumbing used by the PLDM host integration tests.
use core::cell::RefCell;
use mctp::Tag;
use mctp_lib::fragment::{Fragmenter, SendOutput};
use mctp_lib::Sender;
use openprot_mctp_api::{Handle, MctpClient, MctpError, RecvMetadata, ResponseCode};
use openprot_mctp_server::Server;
pub const FD_EID: u8 = 42;
pub const UA_EID: u8 = 8;
pub const TIMEOUT_MILLIS: u32 = 0;
/// MTU for MCTP payload (without header)
const MCTP_MTU: usize = 255;
/// MCTP header size (4 bytes)
const MCTP_HEADER_SIZE: usize = 4;
pub struct BufferSender<'a> {
pub packets: &'a RefCell<Vec<Vec<u8>>>,
}
impl Sender for BufferSender<'_> {
fn send_vectored(
&mut self,
mut fragmenter: Fragmenter,
payload: &[&[u8]],
) -> mctp::Result<Tag> {
loop {
// Fragmenter requires the output buffer to be at least the payload
// MTU (255) plus the 4-byte MCTP transport header.
let mut buf = [0u8; MCTP_MTU + MCTP_HEADER_SIZE];
match fragmenter.fragment_vectored(payload, &mut buf) {
SendOutput::Packet(p) => self.packets.borrow_mut().push(p.to_vec()),
SendOutput::Complete { tag, .. } => return Ok(tag),
SendOutput::Error { err, .. } => return Err(err),
}
}
}
fn get_mtu(&self) -> usize {
MCTP_MTU
}
}
pub fn transfer<S: Sender, const N: usize>(
packets: &RefCell<Vec<Vec<u8>>>,
dest: &mut Server<S, N>,
) {
let pkts = packets.borrow();
for pkt in pkts.iter() {
dest.inbound(pkt).expect("inbound should accept packet");
}
}
pub struct DirectClientWithPump<'a, S: Sender, const N: usize, F: FnMut()> {
pub server: &'a RefCell<Server<S, N>>,
pub pre_recv_pump: RefCell<F>,
}
impl<'a, S: Sender, const N: usize, F: FnMut()> DirectClientWithPump<'a, S, N, F> {
pub fn new(server: &'a RefCell<Server<S, N>>, pre_recv_pump: F) -> Self {
Self {
server,
pre_recv_pump: RefCell::new(pre_recv_pump),
}
}
}
impl<S: Sender, const N: usize, F: FnMut()> MctpClient for DirectClientWithPump<'_, S, N, F> {
fn req(&self, eid: u8) -> Result<Handle, MctpError> {
self.server.borrow_mut().req(eid)
}
fn listener(&self, msg_type: u8) -> Result<Handle, MctpError> {
self.server.borrow_mut().listener(msg_type)
}
fn get_eid(&self) -> u8 {
self.server.borrow().get_eid()
}
fn set_eid(&self, eid: u8) -> Result<(), MctpError> {
self.server.borrow_mut().set_eid(eid)
}
fn recv(
&self,
handle: Handle,
_timeout_millis: u32,
buf: &mut [u8],
) -> Result<RecvMetadata, MctpError> {
(self.pre_recv_pump.borrow_mut())();
self.server
.borrow_mut()
.try_recv(handle, buf)
.ok_or(MctpError::from_code(ResponseCode::TimedOut))
}
fn send(
&self,
handle: Option<Handle>,
msg_type: u8,
eid: Option<u8>,
tag: Option<u8>,
integrity_check: bool,
buf: &[u8],
) -> Result<u8, MctpError> {
self.server
.borrow_mut()
.send(handle, msg_type, eid, tag, integrity_check, buf)
}
fn drop_handle(&self, handle: Handle) {
let _ = self.server.borrow_mut().unbind(handle);
}
}