use crate::mctp_traits::MCTPHeader;
#[derive(Debug, PartialEq)]
pub enum MessageType {
MCtpControl = 0x00,
SpdmOverMctp = 0x05,
SecuredMessages = 0x06,
VendorDefinedPCI = 0x7E,
VendorDefinedIANA = 0x7F,
Invalid = 0xFF,
}
impl From<u8> for MessageType {
fn from(num: u8) -> MessageType {
match num {
0x00 => MessageType::MCtpControl,
0x05 => MessageType::SpdmOverMctp,
0x06 => MessageType::SecuredMessages,
0x7E => MessageType::VendorDefinedPCI,
0x7F => MessageType::VendorDefinedIANA,
_ => MessageType::Invalid,
}
}
}
bitfield! {
pub struct MCTPTransportHeader(MSB0 [u8]);
u8;
rsvd, _ : 3, 0;
pub hdr_version, set_hdr_version: 7, 4;
pub dest_endpoint_id, set_dest_endpoint_id: 15, 8;
pub source_endpoint_id, set_source_endpoint_id: 23, 16;
pub som, set_som: 24, 24;
pub eom, set_eom: 25, 25;
pub pkt_seq, set_pkt_seq: 27, 26;
pub to, set_to: 28, 28;
pub msg_tag, set_msg_tag: 31, 29;
}
impl MCTPTransportHeader<[u8; 4]> {
pub fn new(version: u8) -> Self {
let buf = [0; 4];
let mut tran_header = MCTPTransportHeader(buf);
tran_header.set_hdr_version(version);
tran_header
}
pub fn new_from_buf(buf: [u8; 4], version: u8) -> Result<Self, ()> {
let header = MCTPTransportHeader(buf);
if header.rsvd() != 0x00 {
return Err(());
}
if header.hdr_version() != version {
return Err(());
}
Ok(header)
}
}
bitfield! {
pub struct MCTPMessageBodyHeader(MSB0 [u8]);
u8;
ic, set_ic: 0, 0;
pub msg_type, set_msg_type: 7, 1;
}
impl MCTPMessageBodyHeader<[u8; 1]> {
pub fn new(ic: bool, msg_type: MessageType) -> Self {
let buf = [0; 1];
let mut body_header = MCTPMessageBodyHeader(buf);
if ic {
panic!("Message Integrity bit is currently not supported");
}
body_header.set_ic(ic as u8);
body_header.set_msg_type(msg_type as u8);
body_header
}
pub fn new_from_buf(buf: [u8; 1]) -> Result<Self, ()> {
let header = MCTPMessageBodyHeader(buf);
if header.ic() != 0x00 {
return Err(());
}
if MessageType::from(header.msg_type()) == MessageType::Invalid {
return Err(());
}
Ok(header)
}
}
pub struct MCTPMessageBody<'a, 'b> {
header: &'b MCTPMessageBodyHeader<[u8; 1]>,
pub(crate) additional_header: Option<&'a [u8]>,
pub(crate) data: &'a [u8],
mic: Option<&'a [u8]>,
}
impl<'a, 'b> MCTPMessageBody<'a, 'b> {
pub fn new(
header: &'b MCTPMessageBodyHeader<[u8; 1]>,
additional_header: Option<&'a [u8]>,
data: &'a [u8],
mic: Option<&'a [u8]>,
) -> Self {
Self {
header,
additional_header,
data,
mic,
}
}
}
impl<'a, 'b> MCTPHeader for MCTPMessageBody<'a, 'b> {
fn len(&self) -> usize {
let mut offset = 0;
offset += 1;
if let Some(head_buf) = &self.additional_header {
offset += head_buf.len();
}
offset += self.data.len();
if let Some(mic_buf) = &self.mic {
offset += mic_buf.len();
}
offset
}
fn to_raw_bytes(&self, buf: &mut [u8]) -> usize {
let mut offset = 0;
buf[offset..(offset + 1)].copy_from_slice(&self.header.0);
offset += 1;
if let Some(head_buf) = &self.additional_header {
buf[offset..(offset + head_buf.len())].copy_from_slice(head_buf);
offset += head_buf.len();
}
buf[offset..(offset + self.data.len())].copy_from_slice(self.data);
offset += self.data.len();
if let Some(mic_buf) = &self.mic {
buf[offset..(offset + mic_buf.len())].copy_from_slice(mic_buf);
offset += mic_buf.len();
}
offset
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_transport_header() {
const VERSION: u8 = 0b001;
const DEST_ID: u8 = 0x23;
const SOURCE_ID: u8 = 0x23;
let mut tran_header = MCTPTransportHeader::new(VERSION);
tran_header.set_dest_endpoint_id(DEST_ID);
tran_header.set_source_endpoint_id(SOURCE_ID);
tran_header.set_som(false as u8);
tran_header.set_eom(false as u8);
tran_header.set_pkt_seq(0);
tran_header.set_to(false as u8);
tran_header.set_msg_tag(0);
assert_eq!(tran_header.hdr_version(), VERSION);
assert_eq!(tran_header.dest_endpoint_id(), DEST_ID);
assert_eq!(tran_header.source_endpoint_id(), SOURCE_ID);
}
#[test]
fn test_message_body_header() {
let body_header = MCTPMessageBodyHeader::new(false, MessageType::MCtpControl);
assert_eq!(body_header.ic(), 0);
assert_eq!(body_header.msg_type(), MessageType::MCtpControl as u8);
}
#[test]
fn test_message_body() {
let header: MCTPMessageBodyHeader<[u8; 1]> =
MCTPMessageBodyHeader::new(false, MessageType::VendorDefinedPCI);
let additional_header = None;
let data: [u8; 4] = [0x11; 4];
let mic = None;
let body = MCTPMessageBody::new(&header, additional_header, &data, mic);
let mut buf: [u8; 32] = [0; 32];
let len = body.to_raw_bytes(&mut buf);
assert_eq!(len, 5);
assert_eq!(buf[0], MessageType::VendorDefinedPCI as u8);
}
}