use crate::control_packet::{
CommandCode, CompletionCode, MCTPControlMessageHeader, MCTPGetEndpointIDEndpointIDType,
MCTPGetEndpointIDEndpointType, MCTPSetEndpointIDAllocationStatus,
MCTPSetEndpointIDAssignmentStatus,
};
use crate::mctp_traits::SMBusMCTPRequestResponse;
use core::cell::Cell;
pub struct MCTPSMBusContextResponse {
address: u8,
eid: Cell<u8>,
}
impl SMBusMCTPRequestResponse for MCTPSMBusContextResponse {
fn get_address(&self) -> u8 {
self.address
}
fn get_eid(&self) -> u8 {
self.eid.get()
}
fn set_eid(&self, eid: u8) {
self.eid.replace(eid);
}
}
impl MCTPSMBusContextResponse {
pub fn new(address: u8) -> Self {
Self {
address,
eid: Cell::new(0x00),
}
}
pub fn set_endpoint_id(
&self,
completion_code: CompletionCode,
dest_addr: u8,
assignment_status: MCTPSetEndpointIDAssignmentStatus,
allocation_status: MCTPSetEndpointIDAllocationStatus,
buf: &mut [u8],
) -> Result<usize, ()> {
let command_header =
MCTPControlMessageHeader::new(false, false, 0, CommandCode::SetEndpointID);
let message_header = Some(&(command_header.0[..]));
let mut message_data: [u8; 4] = [
completion_code as u8,
allocation_status as u8,
self.eid.get(),
0x00,
];
if assignment_status == MCTPSetEndpointIDAssignmentStatus::Rejected {
message_data[1] |= 1 << 4;
}
self.generate_packet_bytes(dest_addr, &message_header, &message_data, buf)
}
pub fn get_endpoint_id(
&self,
completion_code: CompletionCode,
dest_addr: u8,
endpoint_type: MCTPGetEndpointIDEndpointType,
endpoint_id_type: MCTPGetEndpointIDEndpointIDType,
fairness_support: bool,
buf: &mut [u8],
) -> Result<usize, ()> {
let command_header =
MCTPControlMessageHeader::new(false, false, 0, CommandCode::GetEndpointID);
let message_header = Some(&(command_header.0[..]));
let message_data: [u8; 4] = [
completion_code as u8,
self.eid.get(),
(endpoint_type as u8) << 4 | endpoint_id_type as u8,
fairness_support as u8,
];
self.generate_packet_bytes(dest_addr, &message_header, &message_data, buf)
}
pub fn get_endpoint_uuid(
&self,
completion_code: CompletionCode,
dest_addr: u8,
uuid: &[u8; 16],
buf: &mut [u8],
) -> Result<usize, ()> {
let command_header =
MCTPControlMessageHeader::new(false, false, 0, CommandCode::GetEndpointUUID);
let message_header = Some(&(command_header.0[..]));
let mut message_data: [u8; 17] = [0; 17];
message_data[0] = completion_code as u8;
message_data[1..17].copy_from_slice(uuid);
self.generate_packet_bytes(dest_addr, &message_header, &message_data, buf)
}
pub fn get_mctp_version_support(
&self,
completion_code: CompletionCode,
dest_addr: u8,
buf: &mut [u8],
) -> Result<usize, ()> {
let command_header =
MCTPControlMessageHeader::new(false, false, 0, CommandCode::GetMCTPVersionSupport);
let message_header = Some(&(command_header.0[..]));
let message_data: [u8; 6] = [completion_code as u8, 1, 0xF1, 0xF3, 0xF1, 0x00];
self.generate_packet_bytes(dest_addr, &message_header, &message_data, buf)
}
pub fn get_message_type_suport(
&self,
completion_code: CompletionCode,
dest_addr: u8,
supported_msg_types: &[u8],
buf: &mut [u8],
) -> Result<usize, ()> {
let command_header =
MCTPControlMessageHeader::new(false, false, 0, CommandCode::GetMessageTypeSupport);
let message_header = Some(&(command_header.0[..]));
let msg_type_count = supported_msg_types.len() as usize;
let mut message_data: [u8; 32] = [0; 32];
message_data[0] = completion_code as u8;
message_data[1] = msg_type_count as u8;
if supported_msg_types.len() > 30 {
return Err(());
}
for (i, d) in supported_msg_types.iter().enumerate() {
message_data[2 + i] = *d;
}
self.generate_packet_bytes(
dest_addr,
&message_header,
&message_data[0..(msg_type_count + 2)],
buf,
)
}
pub fn get_vendor_defined_message_support(
&self,
completion_code: CompletionCode,
dest_addr: u8,
vendor_id_selector: u8,
vendor_id: &[u8],
buf: &mut [u8],
) -> Result<usize, ()> {
let command_header = MCTPControlMessageHeader::new(
false,
false,
0,
CommandCode::GetVendorDefinedMessageSupport,
);
let message_header = Some(&(command_header.0[..]));
let vendor_length = vendor_id.len() as usize;
let mut message_data: [u8; 9] = [
completion_code as u8,
vendor_id_selector,
0,
0,
0,
0,
0,
0,
0,
];
for (i, d) in vendor_id.iter().enumerate() {
message_data[2 + i] = *d;
}
self.generate_packet_bytes(
dest_addr,
&message_header,
&message_data[0..(vendor_length + 2)],
buf,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::base_packet::MessageType;
use crate::smbus_proto::{HDR_VERSION, MCTP_SMBUS_COMMAND_CODE};
#[test]
fn test_generate_smbus_header() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let header = ctx.generate_smbus_header(DEST_ID);
let buf = header.0;
assert_eq!(buf[0], DEST_ID << 1);
assert_eq!(buf[1], MCTP_SMBUS_COMMAND_CODE);
assert_eq!(buf[2], 0);
assert_eq!(buf[3], SOURCE_ID << 1 | 1);
}
#[test]
fn test_generate_transport_header() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let header = ctx.generate_transport_header(DEST_ID);
let buf = header.0;
assert_eq!(buf[0], HDR_VERSION);
assert_eq!(buf[1], DEST_ID);
assert_eq!(buf[2], SOURCE_ID);
assert_eq!(buf[3], 1 << 7 | 1 << 6 | 0 << 4 | 1 << 3 | 0);
}
#[test]
fn test_set_endpoint_id() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
const EID: u8 = 0x78;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let mut buf: [u8; 21] = [0; 21];
ctx.set_eid(EID);
let len = ctx
.set_endpoint_id(
CompletionCode::Success,
DEST_ID,
MCTPSetEndpointIDAssignmentStatus::Accpeted,
MCTPSetEndpointIDAllocationStatus::NoIDPool,
&mut buf,
)
.unwrap();
assert_eq!(len, 16);
assert_eq!(buf[2], 12);
assert_eq!(buf[8], 0 << 7 | MessageType::MCtpControl as u8);
assert_eq!(buf[9], 0 << 7 | 0 << 6 | 0 << 5 | 0);
assert_eq!(buf[10], CommandCode::SetEndpointID as u8);
assert_eq!(buf[11], CompletionCode::Success as u8);
assert_eq!(
buf[12],
(MCTPSetEndpointIDAssignmentStatus::Accpeted as u8) << 4
| MCTPSetEndpointIDAllocationStatus::NoIDPool as u8
);
assert_eq!(buf[13], ctx.get_eid());
assert_eq!(buf[14], 0x00);
}
#[test]
fn test_get_endpoint_id() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
const EID: u8 = 0x78;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let mut buf: [u8; 21] = [0; 21];
ctx.set_eid(EID);
let len = ctx
.get_endpoint_id(
CompletionCode::Success,
DEST_ID,
MCTPGetEndpointIDEndpointType::Simple,
MCTPGetEndpointIDEndpointIDType::DynamicEID,
true,
&mut buf,
)
.unwrap();
assert_eq!(len, 16);
assert_eq!(buf[2], 12);
assert_eq!(buf[8], 0 << 7 | MessageType::MCtpControl as u8);
assert_eq!(buf[9], 0 << 7 | 0 << 6 | 0 << 5 | 0);
assert_eq!(buf[10], CommandCode::GetEndpointID as u8);
assert_eq!(buf[11], CompletionCode::Success as u8);
assert_eq!(buf[12], EID);
assert_eq!(buf[13], 0);
assert_eq!(buf[14], 0x01);
}
#[test]
fn test_get_endpoint_uuid() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
const EID: u8 = 0x78;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let mut buf: [u8; 32] = [0; 32];
ctx.set_eid(EID);
let uuid: [u8; 16] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
0x0E, 0x0F,
];
let len = ctx
.get_endpoint_uuid(CompletionCode::Success, DEST_ID, &uuid, &mut buf)
.unwrap();
assert_eq!(len, 29);
assert_eq!(buf[2], 25);
assert_eq!(buf[8], 0 << 7 | MessageType::MCtpControl as u8);
assert_eq!(buf[9], 0 << 7 | 0 << 6 | 0 << 5 | 0);
assert_eq!(buf[10], CommandCode::GetEndpointUUID as u8);
assert_eq!(buf[11], CompletionCode::Success as u8);
for (i, d) in uuid.iter().enumerate() {
assert_eq!(buf[12 + i], *d);
}
}
#[test]
fn test_get_mctp_version_support() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let mut buf: [u8; 21] = [0; 21];
let len = ctx
.get_mctp_version_support(CompletionCode::Success, DEST_ID, &mut buf)
.unwrap();
assert_eq!(len, 18);
assert_eq!(buf[2], 14);
assert_eq!(buf[8], 0 << 7 | MessageType::MCtpControl as u8);
assert_eq!(buf[9], 0 << 7 | 0 << 6 | 0 << 5 | 0);
assert_eq!(buf[10], CommandCode::GetMCTPVersionSupport as u8);
assert_eq!(buf[11], CompletionCode::Success as u8);
assert_eq!(buf[12], 1);
assert_eq!(buf[13], 0xF1);
assert_eq!(buf[14], 0xF3);
assert_eq!(buf[15], 0xF1);
assert_eq!(buf[16], 0x00);
}
#[test]
fn test_get_message_type_suport() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let mut buf: [u8; 21] = [0; 21];
let msg_types = [0x7E];
let len = ctx
.get_message_type_suport(CompletionCode::Success, DEST_ID, &msg_types, &mut buf)
.unwrap();
assert_eq!(len, 15);
assert_eq!(buf[2], 11);
assert_eq!(buf[8], 0 << 7 | MessageType::MCtpControl as u8);
assert_eq!(buf[9], 0 << 7 | 0 << 6 | 0 << 5 | 0);
assert_eq!(buf[10], CommandCode::GetMessageTypeSupport as u8);
assert_eq!(buf[11], CompletionCode::Success as u8);
assert_eq!(buf[12], msg_types.len() as u8);
assert_eq!(buf[13], msg_types[0]);
}
#[test]
fn test_get_vendor_defined_message_support() {
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
let ctx = MCTPSMBusContextResponse::new(SOURCE_ID);
let mut buf: [u8; 21] = [0; 21];
let vendor_id = [
0x00,
0xAB, 0xBC, 0x12, 0x34,
];
let len = ctx
.get_vendor_defined_message_support(
CompletionCode::Success,
DEST_ID,
0xFF,
&vendor_id,
&mut buf,
)
.unwrap();
assert_eq!(len, 19);
assert_eq!(buf[2], 15);
assert_eq!(buf[8], 0 << 7 | MessageType::MCtpControl as u8);
assert_eq!(buf[9], 0 << 7 | 0 << 6 | 0 << 5 | 0);
assert_eq!(buf[10], CommandCode::GetVendorDefinedMessageSupport as u8);
assert_eq!(buf[11], CompletionCode::Success as u8);
assert_eq!(buf[12], 0xFF);
for (i, d) in vendor_id.iter().enumerate() {
assert_eq!(buf[13 + i], *d);
}
}
}