CFDP initial packet support #14

Merged
muellerr merged 49 commits from cfdp_first_support into main 2023-07-02 17:31:17 +02:00
2 changed files with 53 additions and 26 deletions
Showing only changes of commit bf4e841499 - Show all commits

View File

@ -1,8 +1,8 @@
use crate::cfdp::lv::Lv; use crate::cfdp::lv::Lv;
use crate::cfdp::pdu::{FileDirectiveType, PduError, PduHeader}; use crate::cfdp::pdu::{FileDirectiveType, PduError, PduHeader};
use crate::cfdp::tlv::Tlv; use crate::cfdp::tlv::Tlv;
use crate::cfdp::{ChecksumType, LargeFileFlag}; use crate::cfdp::{ChecksumType, CrcFlag, LargeFileFlag};
use crate::{ByteConversionError, SizeMissmatch}; use crate::{ByteConversionError, SizeMissmatch, CRC_CCITT_FALSE};
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use alloc::vec::Vec; use alloc::vec::Vec;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -74,12 +74,25 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
} }
pub fn new_with_opts( pub fn new_with_opts(
pdu_header: PduHeader, mut pdu_header: PduHeader,
metadata_params: MetadataGenericParams, metadata_params: MetadataGenericParams,
src_file_name: Lv<'src_name>, src_file_name: Lv<'src_name>,
dest_file_name: Lv<'dest_name>, dest_file_name: Lv<'dest_name>,
options: Option<&'opts [u8]>, options: Option<&'opts [u8]>,
) -> Self { ) -> Self {
let is_large_file = pdu_header.common_pdu_conf().file_flag == LargeFileFlag::Large;
let has_crc = pdu_header.common_pdu_conf().crc_flag == CrcFlag::WithCrc;
pdu_header.pdu_datafield_len =
2 + 4 + src_file_name.len_full() as u16 + dest_file_name.len_full() as u16;
if is_large_file {
pdu_header.pdu_datafield_len += 4;
}
if has_crc {
pdu_header.pdu_datafield_len += 2;
}
if let Some(opts) = options {
pdu_header.pdu_datafield_len += opts.len() as u16;
}
Self { Self {
pdu_header, pdu_header,
metadata_params, metadata_params,
@ -114,10 +127,17 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
if let Some(opts) = self.options { if let Some(opts) = self.options {
len += opts.len(); len += opts.len();
} }
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
len += 2;
}
len len
} }
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> { pub fn pdu_header(&self) -> &PduHeader {
&self.pdu_header
}
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.written_len(); let expected_len = self.written_len();
if buf.len() < expected_len { if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall(SizeMissmatch { return Err(ByteConversionError::ToSliceTooSmall(SizeMissmatch {
@ -126,7 +146,8 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
}) })
.into()); .into());
} }
let mut current_idx = self.pdu_header.write_to_be_bytes(buf)?;
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
buf[current_idx] = FileDirectiveType::MetadataPdu as u8; buf[current_idx] = FileDirectiveType::MetadataPdu as u8;
current_idx += 1; current_idx += 1;
buf[current_idx] = ((self.metadata_params.closure_requested as u8) << 7) buf[current_idx] = ((self.metadata_params.closure_requested as u8) << 7)
@ -154,13 +175,19 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
buf[current_idx..current_idx + opts.len()].copy_from_slice(opts); buf[current_idx..current_idx + opts.len()].copy_from_slice(opts);
current_idx += opts.len(); current_idx += opts.len();
} }
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
let mut digest = CRC_CCITT_FALSE.digest();
digest.update(&buf[..current_idx]);
buf[current_idx..current_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes());
current_idx += 2;
}
Ok(current_idx) Ok(current_idx)
} }
pub fn from_be_bytes<'longest: 'src_name + 'dest_name + 'opts>( pub fn from_bytes<'longest: 'src_name + 'dest_name + 'opts>(
buf: &'longest [u8], buf: &'longest [u8],
) -> Result<MetadataPdu<'src_name, 'dest_name, 'opts>, PduError> { ) -> Result<MetadataPdu<'src_name, 'dest_name, 'opts>, PduError> {
let (pdu_header, mut current_idx) = PduHeader::from_be_bytes(buf)?; let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?;
let full_len_without_crc = pdu_header.verify_length_and_checksum(buf)?; let full_len_without_crc = pdu_header.verify_length_and_checksum(buf)?;
let is_large_file = pdu_header.pdu_conf.file_flag == LargeFileFlag::Large; let is_large_file = pdu_header.pdu_conf.file_flag == LargeFileFlag::Large;
// Minimal length: 1 byte + FSS (4 byte) + 2 empty LV (1 byte) // Minimal length: 1 byte + FSS (4 byte) + 2 empty LV (1 byte)
@ -272,14 +299,14 @@ pub mod tests {
let metadata_pdu = let metadata_pdu =
MetadataPdu::new(pdu_header, metadata_params, src_filename, dest_filename); MetadataPdu::new(pdu_header, metadata_params, src_filename, dest_filename);
let mut buf: [u8; 64] = [0; 64]; let mut buf: [u8; 64] = [0; 64];
let res = metadata_pdu.write_to_be_bytes(&mut buf); let res = metadata_pdu.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
let written = res.unwrap(); let written = res.unwrap();
assert_eq!( assert_eq!(
written, written,
pdu_header.header_len() + 1 + 1 + 4 + src_len + dest_len pdu_header.header_len() + 1 + 1 + 4 + src_len + dest_len
); );
verify_raw_header(&pdu_header, &buf); verify_raw_header(metadata_pdu.pdu_header(), &buf);
assert_eq!(buf[7], FileDirectiveType::MetadataPdu as u8); assert_eq!(buf[7], FileDirectiveType::MetadataPdu as u8);
assert_eq!(buf[8] >> 6, false as u8); assert_eq!(buf[8] >> 6, false as u8);
assert_eq!(buf[8] & 0b1111, ChecksumType::Crc32 as u8); assert_eq!(buf[8] & 0b1111, ChecksumType::Crc32 as u8);

View File

@ -257,7 +257,7 @@ impl PduHeader {
self.header_len() + self.pdu_datafield_len as usize self.header_len() + self.pdu_datafield_len as usize
} }
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> { pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
// Internal note: There is currently no way to pass a PDU configuration like this, but // Internal note: There is currently no way to pass a PDU configuration like this, but
// this check is still kept for defensive programming. // this check is still kept for defensive programming.
if self.pdu_conf.source_entity_id.len() != self.pdu_conf.dest_entity_id.len() { if self.pdu_conf.source_entity_id.len() != self.pdu_conf.dest_entity_id.len() {
@ -340,7 +340,7 @@ impl PduHeader {
/// to hold the full PDU. /// to hold the full PDU.
/// ///
/// Both functions can however be performed with the [verify_length_and_checksum] function. /// Both functions can however be performed with the [verify_length_and_checksum] function.
pub fn from_be_bytes(buf: &[u8]) -> Result<(Self, usize), PduError> { pub fn from_bytes(buf: &[u8]) -> Result<(Self, usize), PduError> {
if buf.len() < FIXED_HEADER_LEN { if buf.len() < FIXED_HEADER_LEN {
return Err(PduError::ByteConversionError( return Err(PduError::ByteConversionError(
ByteConversionError::FromSliceTooSmall(SizeMissmatch { ByteConversionError::FromSliceTooSmall(SizeMissmatch {
@ -546,7 +546,7 @@ mod tests {
.expect("common config creation failed"); .expect("common config creation failed");
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
let mut buf: [u8; 7] = [0; 7]; let mut buf: [u8; 7] = [0; 7];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
// 4 byte fixed header plus three bytes src, dest ID and transaction ID // 4 byte fixed header plus three bytes src, dest ID and transaction ID
assert_eq!(res.unwrap(), 7); assert_eq!(res.unwrap(), 7);
@ -562,9 +562,9 @@ mod tests {
.expect("common config creation failed"); .expect("common config creation failed");
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
let mut buf: [u8; 7] = [0; 7]; let mut buf: [u8; 7] = [0; 7];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
let deser_res = PduHeader::from_be_bytes(&buf); let deser_res = PduHeader::from_bytes(&buf);
assert!(deser_res.is_ok()); assert!(deser_res.is_ok());
let (header_read_back, read_size) = deser_res.unwrap(); let (header_read_back, read_size) = deser_res.unwrap();
assert_eq!(read_size, 7); assert_eq!(read_size, 7);
@ -591,7 +591,7 @@ mod tests {
); );
assert_eq!(pdu_header.header_len(), 10); assert_eq!(pdu_header.header_len(), 10);
let mut buf: [u8; 16] = [0; 16]; let mut buf: [u8; 16] = [0; 16];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok(), "{}", format!("Result {res:?} not okay")); assert!(res.is_ok(), "{}", format!("Result {res:?} not okay"));
// 4 byte fixed header, 6 bytes additional fields // 4 byte fixed header, 6 bytes additional fields
assert_eq!(res.unwrap(), 10); assert_eq!(res.unwrap(), 10);
@ -617,9 +617,9 @@ mod tests {
SegmentationControl::WithRecordBoundaryPreservation, SegmentationControl::WithRecordBoundaryPreservation,
); );
let mut buf: [u8; 16] = [0; 16]; let mut buf: [u8; 16] = [0; 16];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
let deser_res = PduHeader::from_be_bytes(&buf); let deser_res = PduHeader::from_bytes(&buf);
assert!(deser_res.is_ok()); assert!(deser_res.is_ok());
let (header_read_back, read_size) = deser_res.unwrap(); let (header_read_back, read_size) = deser_res.unwrap();
assert_eq!(read_size, 10); assert_eq!(read_size, 10);
@ -635,11 +635,11 @@ mod tests {
.expect("common config creation failed"); .expect("common config creation failed");
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
let mut buf: [u8; 7] = [0; 7]; let mut buf: [u8; 7] = [0; 7];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
buf[0] &= !0b1110_0000; buf[0] &= !0b1110_0000;
buf[0] |= (CFDP_VERSION_2 + 1) << 5; buf[0] |= (CFDP_VERSION_2 + 1) << 5;
let res = PduHeader::from_be_bytes(&buf); let res = PduHeader::from_bytes(&buf);
assert!(res.is_err()); assert!(res.is_err());
let error = res.unwrap_err(); let error = res.unwrap_err();
if let PduError::CfdpVersionMissmatch(raw_version) = error { if let PduError::CfdpVersionMissmatch(raw_version) = error {
@ -652,7 +652,7 @@ mod tests {
#[test] #[test]
fn test_buf_too_small_1() { fn test_buf_too_small_1() {
let buf: [u8; 3] = [0; 3]; let buf: [u8; 3] = [0; 3];
let res = PduHeader::from_be_bytes(&buf); let res = PduHeader::from_bytes(&buf);
assert!(res.is_err()); assert!(res.is_err());
let error = res.unwrap_err(); let error = res.unwrap_err();
if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) = if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) =
@ -674,9 +674,9 @@ mod tests {
.expect("common config creation failed"); .expect("common config creation failed");
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
let mut buf: [u8; 7] = [0; 7]; let mut buf: [u8; 7] = [0; 7];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
let header = PduHeader::from_be_bytes(&buf[0..6]); let header = PduHeader::from_bytes(&buf[0..6]);
assert!(header.is_err()); assert!(header.is_err());
let error = header.unwrap_err(); let error = header.unwrap_err();
if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) = if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) =
@ -737,12 +737,12 @@ mod tests {
.expect("common config creation failed"); .expect("common config creation failed");
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
let mut buf: [u8; 7] = [0; 7]; let mut buf: [u8; 7] = [0; 7];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
buf[3] &= !0b0111_0000; buf[3] &= !0b0111_0000;
// Equivalent to the length of three // Equivalent to the length of three
buf[3] |= 0b10 << 4; buf[3] |= 0b10 << 4;
let header_res = PduHeader::from_be_bytes(&buf); let header_res = PduHeader::from_bytes(&buf);
assert!(header_res.is_err()); assert!(header_res.is_err());
let error = header_res.unwrap_err(); let error = header_res.unwrap_err();
if let PduError::InvalidEntityLen(len) = error { if let PduError::InvalidEntityLen(len) = error {
@ -761,12 +761,12 @@ mod tests {
.expect("common config creation failed"); .expect("common config creation failed");
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
let mut buf: [u8; 7] = [0; 7]; let mut buf: [u8; 7] = [0; 7];
let res = pdu_header.write_to_be_bytes(&mut buf); let res = pdu_header.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
buf[3] &= !0b0000_0111; buf[3] &= !0b0000_0111;
// Equivalent to the length of three // Equivalent to the length of three
buf[3] |= 0b10; buf[3] |= 0b10;
let header_res = PduHeader::from_be_bytes(&buf); let header_res = PduHeader::from_bytes(&buf);
assert!(header_res.is_err()); assert!(header_res.is_err());
let error = header_res.unwrap_err(); let error = header_res.unwrap_err();
if let PduError::InvalidTransactionSeqNumLen(len) = error { if let PduError::InvalidTransactionSeqNumLen(len) = error {