-
Notifications
You must be signed in to change notification settings - Fork 7
Open
Description
Integrating the SPDM responder task (using spdm-lib) into Hubris revealed an API mismatch with the mctp-rs transport layer.
Let's examine the mctp-echo sample to understand this issue:
MCTP Echo: Simple, Direct Flow
fn main() -> ! {
let stack = mctp_api::Stack::from(MCTP.get_task_id());
stack.set_eid(Eid(8)).unwrap_lite();
let mut listener = stack.listener(MsgType(1), None).unwrap_lite();
let mut recv_buf = [0; 255];
loop {
// 1. Receive message with RespChannel
let (_, _, msg, mut resp) = listener.recv(&mut recv_buf).unwrap_lite();
// 2. Immediately send response using RespChannel
match resp.send(msg) {
Ok(_) => {}
Err(_e) => { /* handle error */ }
}
// 3. RespChannel drops here - perfect lifecycle
}
}Key Characteristics of Echo Pattern
- Immediate Processing: Receive → Process → Respond in same scope
- Direct RespChannel Usage: Uses the channel returned by
recv()directly - No Storage Required: RespChannel used immediately, then dropped
- Perfect Tag Correlation: Automatic MCTP tag correlation via RespChannel
- Simple Lifetime Management: No lifetime conflicts
Why Echo Pattern Works Perfectly
let (msg_type, msg_ic, msg, mut resp_channel) = listener.recv(&mut recv_buf)?;
// ^^^^^^^^^^^^^^^^
// resp_channel used immediately in same scope
resp_channel.send(response_data)?; // ← Uses original tag automatically
// resp_channel drops here - no lifetime issuesMCTP Flow:
- Client sends request with tag
0x42 - Echo receives with RespChannel containing tag
0x42 - Echo responds via RespChannel.send() with tag
0x42 - Client correlates perfectly - same tag!
SPDM Responder: Complex, Deferred Flow
Complex, Deferred Flow
impl SpdmTransport for MctpSpdmTransport {
// 1. RECEIVE PHASE: Store metadata, can't store RespChannel
fn receive_request(&mut self, req: &mut MessageBuf) -> TransportResult<()> {
let (msg_type, _msg_ic, msg, resp_channel) = self.listener.recv(&mut self.buffer)?;
// PROBLEM: Cannot store resp_channel due to lifetimes
// self.pending_resp_channel = Some(resp_channel); // ← COMPILATION ERROR
// WORKAROUND: Extract metadata only
self.pending_eid = Some(resp_channel.remote_eid());
self.pending_msg_type = Some(msg_type);
// resp_channel DROPS HERE - tag information lost!
// Copy message for later processing
// ... message buffer operations
}
// 2. PROCESSING PHASE: spdm-lib processes the message
// (Happens outside transport, in main loop)
// 3. RESPONSE PHASE: Create new channel, losing tag correlation
fn send_response(&mut self, resp: &mut MessageBuf) -> TransportResult<()> {
let eid = self.pending_eid.take().unwrap();
let typ = self.pending_msg_type.unwrap();
// PROBLEM: Create NEW channel with NEW tag
let mut req_chan = self.stack.req(eid, None)?;
req_chan.send(typ, response_data)?; // ← Creates fresh tag!
}
}Why SPDM Pattern Breaks
The SPDM responder cannot use the echo pattern because:
1. Architectural Constraint: spdm-lib Interface
// spdm-lib expects this trait interface
trait SpdmTransport {
fn receive_request(&mut self, req: &mut MessageBuf) -> Result<()>; // Phase 1
fn send_response(&mut self, resp: &mut MessageBuf) -> Result<()>; // Phase 3
}
// Phase 2 (processing) happens BETWEEN these calls in spdm-libThe problem: receive_request() and send_response() are separate function calls with different scopes, but RespChannel has a lifetime tied to the recv() call.
2. Temporal Separation
// MCTP Echo: Single scope
let (_, _, msg, mut resp) = listener.recv(&mut buf)?;
resp.send(process_immediately(msg))?; // Same scope - works!
// SPDM Responder: Multi-scope
fn receive_request() {
let (_, _, msg, resp) = listener.recv(&mut buf)?;
// resp must be used HERE or lost forever
// But spdm-lib wants to process message later!
}
// ... time passes, spdm-lib processes ...
fn send_response() {
// resp is long gone - need new channel
}RespChannel has a lifetime to the recv call.
// mctp-api types are inherently tied to stack lifetime
pub struct MctpListener<'r> {
stack: &'r Stack, // ← Lifetime tied to stack
handle: ipc::GenericHandle,
timeout: u32,
}
pub struct MctpRespChannel<'r> {
stack: &'r Stack, // ← Same constraint
handle: ipc::GenericHandle,
eid: Eid,
typ: MsgType,
tv: TagValue,
}I have tried to workaround the impedance mismatch by creating a request channel, but if I do that ReqChannel: Allocates new tag → ❌ Appears as independent request, not response.
According to MCTP specification (DSP0236), request/response pairs must share the same tag:
- Client sends request with tag 0x42
- Server must respond with tag 0x42 (same tag)
- Client correlates response using tag matching
Metadata
Metadata
Assignees
Labels
No labels