Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ authors = ["Caliptra contributors", "OpenPRoT contributors"]
edition = "2024"

[dependencies]
zerocopy = {version = "0.8.17", features = ["derive"]}
zerocopy = { version = "0.8.17", features = ["derive"] }
bitfield = "0.14.0"
33 changes: 33 additions & 0 deletions src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes};
pub enum PldmCodecError {
BufferTooShort,
Unsupported,
InvalidData,
}

/// A trait for encoding and decoding PLDM (Platform Level Data Model) messages.
Expand Down Expand Up @@ -37,7 +38,39 @@ pub trait PldmCodec: core::fmt::Debug + Sized {
fn decode(buffer: &[u8]) -> Result<Self, PldmCodecError>;
}

/// A trait for encoding and decoding PLDM messages with explicit lifetime requirements.
///
/// This trait is similar to `PldmCodec` but supports types that borrow data from the buffer
/// during decoding, requiring an explicit lifetime parameter.
pub trait PldmCodecWithLifetime<'a>: core::fmt::Debug + Sized {
/// Encodes the PLDM message into the provided byte buffer.
///
/// # Arguments
///
/// * `buffer` - A mutable reference to a byte slice where the encoded message will be stored.
///
/// # Returns
///
/// A `Result` containing the size of the encoded message on success, or a `PldmCodecError` on failure.
fn encode(&self, buffer: &mut [u8]) -> Result<usize, PldmCodecError>;

/// Decodes a PLDM message from the provided byte buffer.
///
/// # Arguments
///
/// * `buffer` - A reference to a byte slice containing the encoded message. The decoded
/// type may hold references to this buffer.
///
/// # Returns
///
/// A `Result` containing the decoded message on success, or a `PldmCodecError` on failure.
fn decode(buffer: &'a [u8]) -> Result<Self, PldmCodecError>;
}

// Default implementation of PldmCodec for types that can leverage zerocopy.
// TODO: can we generalize this to use sub-struct encodes when possible?
// There are structs like PldmFirmwareString that contain variable-length data
// that would need special handling.
impl<T> PldmCodec for T
where
T: core::fmt::Debug + Sized + FromBytes + IntoBytes + Immutable,
Expand Down
48 changes: 43 additions & 5 deletions src/message/firmware_update/get_fw_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,7 @@ impl PldmCodec for GetFirmwareParametersResponse {
offset += core::mem::size_of::<u8>();

let bytes = self.parms.encode(&mut buffer[offset..])?;
offset += bytes;
Ok(offset)
Ok(offset + bytes)
}

fn decode(buffer: &[u8]) -> Result<Self, PldmCodecError> {
Expand Down Expand Up @@ -331,32 +330,71 @@ mod test {
}

#[test]
fn test_get_firmware_parameters_request() {
fn test_get_firmware_parameters_request_codec() {
let request = GetFirmwareParametersRequest::new(0, PldmMsgType::Request);
let mut buffer = [0u8; PLDM_MSG_HEADER_LEN];
request.encode(&mut buffer).unwrap();

let decoded_request = GetFirmwareParametersRequest::decode(&buffer).unwrap();
assert_eq!(request, decoded_request);

// Test buffer too short error
let mut buffer = [0u8; PLDM_MSG_HEADER_LEN - 1];
assert_eq!(
request.encode(&mut buffer).unwrap_err(),
PldmCodecError::BufferTooShort
);

assert_eq!(
GetFirmwareParametersRequest::decode(&buffer).unwrap_err(),
PldmCodecError::BufferTooShort
);
}

#[test]
fn test_get_firmware_parameters() {
fn test_get_firmware_parameters_codec() {
let firmware_parameters = construct_firmware_params();
let mut buffer = [0u8; 1024];
let size = firmware_parameters.encode(&mut buffer).unwrap();
assert_eq!(size, firmware_parameters.codec_size_in_bytes());

let decoded_firmware_parameters = FirmwareParameters::decode(&buffer[..size]).unwrap();
assert_eq!(firmware_parameters, decoded_firmware_parameters);

// Test buffer too short error
let mut short_buffer = [0u8; 1];
assert_eq!(
firmware_parameters.encode(&mut short_buffer).unwrap_err(),
PldmCodecError::BufferTooShort
);

assert_eq!(
FirmwareParameters::decode(&short_buffer).unwrap_err(),
PldmCodecError::BufferTooShort
);
}

#[test]
fn test_get_firmware_parameters_response() {
fn test_get_firmware_parameters_response_codec() {
let firmware_parameters = construct_firmware_params();
let response = GetFirmwareParametersResponse::new(0, 0, &firmware_parameters);
let mut buffer = [0u8; 1024];
let size = response.encode(&mut buffer).unwrap();
assert_eq!(size, response.codec_size_in_bytes());

let decoded_response = GetFirmwareParametersResponse::decode(&buffer[..size]).unwrap();
assert_eq!(response, decoded_response);

// Test buffer too short error
let mut short_buffer = [0u8; 1];
assert_eq!(
response.encode(&mut short_buffer).unwrap_err(),
PldmCodecError::BufferTooShort
);

assert_eq!(
GetFirmwareParametersResponse::decode(&short_buffer).unwrap_err(),
PldmCodecError::BufferTooShort
);
}
}
Loading