From bf4e8414990144bae94e0e800e9f3f892687f2ce Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 29 May 2023 14:28:15 +0200 Subject: [PATCH] added correct PDU datafield length handling --- src/cfdp/pdu/metadata.rs | 45 ++++++++++++++++++++++++++++++++-------- src/cfdp/pdu/mod.rs | 34 +++++++++++++++--------------- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/src/cfdp/pdu/metadata.rs b/src/cfdp/pdu/metadata.rs index 91f992b..37e6cac 100644 --- a/src/cfdp/pdu/metadata.rs +++ b/src/cfdp/pdu/metadata.rs @@ -1,8 +1,8 @@ use crate::cfdp::lv::Lv; use crate::cfdp::pdu::{FileDirectiveType, PduError, PduHeader}; use crate::cfdp::tlv::Tlv; -use crate::cfdp::{ChecksumType, LargeFileFlag}; -use crate::{ByteConversionError, SizeMissmatch}; +use crate::cfdp::{ChecksumType, CrcFlag, LargeFileFlag}; +use crate::{ByteConversionError, SizeMissmatch, CRC_CCITT_FALSE}; #[cfg(feature = "alloc")] use alloc::vec::Vec; #[cfg(feature = "serde")] @@ -74,12 +74,25 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> { } pub fn new_with_opts( - pdu_header: PduHeader, + mut pdu_header: PduHeader, metadata_params: MetadataGenericParams, src_file_name: Lv<'src_name>, dest_file_name: Lv<'dest_name>, options: Option<&'opts [u8]>, ) -> 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 { pdu_header, metadata_params, @@ -114,10 +127,17 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> { if let Some(opts) = self.options { len += opts.len(); } + if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { + len += 2; + } len } - pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + pub fn pdu_header(&self) -> &PduHeader { + &self.pdu_header + } + + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { let expected_len = self.written_len(); if buf.len() < expected_len { return Err(ByteConversionError::ToSliceTooSmall(SizeMissmatch { @@ -126,7 +146,8 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> { }) .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; current_idx += 1; 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); 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) } - pub fn from_be_bytes<'longest: 'src_name + 'dest_name + 'opts>( + pub fn from_bytes<'longest: 'src_name + 'dest_name + 'opts>( buf: &'longest [u8], ) -> Result, 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 is_large_file = pdu_header.pdu_conf.file_flag == LargeFileFlag::Large; // Minimal length: 1 byte + FSS (4 byte) + 2 empty LV (1 byte) @@ -272,14 +299,14 @@ pub mod tests { let metadata_pdu = MetadataPdu::new(pdu_header, metadata_params, src_filename, dest_filename); 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()); let written = res.unwrap(); assert_eq!( written, 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[8] >> 6, false as u8); assert_eq!(buf[8] & 0b1111, ChecksumType::Crc32 as u8); diff --git a/src/cfdp/pdu/mod.rs b/src/cfdp/pdu/mod.rs index e2fd887..c443d3a 100644 --- a/src/cfdp/pdu/mod.rs +++ b/src/cfdp/pdu/mod.rs @@ -257,7 +257,7 @@ impl PduHeader { self.header_len() + self.pdu_datafield_len as usize } - pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { // Internal note: There is currently no way to pass a PDU configuration like this, but // this check is still kept for defensive programming. 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. /// /// 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 { return Err(PduError::ByteConversionError( ByteConversionError::FromSliceTooSmall(SizeMissmatch { @@ -546,7 +546,7 @@ mod tests { .expect("common config creation failed"); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); 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()); // 4 byte fixed header plus three bytes src, dest ID and transaction ID assert_eq!(res.unwrap(), 7); @@ -562,9 +562,9 @@ mod tests { .expect("common config creation failed"); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); 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()); - let deser_res = PduHeader::from_be_bytes(&buf); + let deser_res = PduHeader::from_bytes(&buf); assert!(deser_res.is_ok()); let (header_read_back, read_size) = deser_res.unwrap(); assert_eq!(read_size, 7); @@ -591,7 +591,7 @@ mod tests { ); assert_eq!(pdu_header.header_len(), 10); 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")); // 4 byte fixed header, 6 bytes additional fields assert_eq!(res.unwrap(), 10); @@ -617,9 +617,9 @@ mod tests { SegmentationControl::WithRecordBoundaryPreservation, ); 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()); - let deser_res = PduHeader::from_be_bytes(&buf); + let deser_res = PduHeader::from_bytes(&buf); assert!(deser_res.is_ok()); let (header_read_back, read_size) = deser_res.unwrap(); assert_eq!(read_size, 10); @@ -635,11 +635,11 @@ mod tests { .expect("common config creation failed"); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); 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()); buf[0] &= !0b1110_0000; buf[0] |= (CFDP_VERSION_2 + 1) << 5; - let res = PduHeader::from_be_bytes(&buf); + let res = PduHeader::from_bytes(&buf); assert!(res.is_err()); let error = res.unwrap_err(); if let PduError::CfdpVersionMissmatch(raw_version) = error { @@ -652,7 +652,7 @@ mod tests { #[test] fn test_buf_too_small_1() { let buf: [u8; 3] = [0; 3]; - let res = PduHeader::from_be_bytes(&buf); + let res = PduHeader::from_bytes(&buf); assert!(res.is_err()); let error = res.unwrap_err(); if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) = @@ -674,9 +674,9 @@ mod tests { .expect("common config creation failed"); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); 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()); - let header = PduHeader::from_be_bytes(&buf[0..6]); + let header = PduHeader::from_bytes(&buf[0..6]); assert!(header.is_err()); let error = header.unwrap_err(); if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) = @@ -737,12 +737,12 @@ mod tests { .expect("common config creation failed"); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); 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()); buf[3] &= !0b0111_0000; // Equivalent to the length of three buf[3] |= 0b10 << 4; - let header_res = PduHeader::from_be_bytes(&buf); + let header_res = PduHeader::from_bytes(&buf); assert!(header_res.is_err()); let error = header_res.unwrap_err(); if let PduError::InvalidEntityLen(len) = error { @@ -761,12 +761,12 @@ mod tests { .expect("common config creation failed"); let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5); 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()); buf[3] &= !0b0000_0111; // Equivalent to the length of three buf[3] |= 0b10; - let header_res = PduHeader::from_be_bytes(&buf); + let header_res = PduHeader::from_bytes(&buf); assert!(header_res.is_err()); let error = header_res.unwrap_err(); if let PduError::InvalidTransactionSeqNumLen(len) = error {