1use bon::bon;
37use zerocopy::FromBytes;
38use zerocopy::Immutable;
39use zerocopy::IntoBytes;
40use zerocopy::KnownLayout;
41use zerocopy::Unaligned;
42use zerocopy::byteorder::network_endian::{U16, U32};
43
44use crate::ids::{Scid, Vcid};
45use crate::utils::{get_bits_u8, get_bits_u32, set_bits_u8, set_bits_u32};
46
47pub const USLP_TFVN: u8 = 0b1100;
49
50pub const OID_VCID: u8 = 63;
52
53#[rustfmt::skip]
55pub mod bitmask {
56 pub const TFVN_MASK: u32 = 0xF000_0000;
60 pub const SCID_MASK: u32 = 0x0FFF_F000;
62 pub const SRC_DEST_MASK: u32 = 0x0000_0800;
64 pub const VCID_MASK: u32 = 0x0000_07E0;
66 pub const MAP_ID_MASK: u32 = 0x0000_001E;
68 pub const EOFPH_MASK: u32 = 0x0000_0001;
70
71 pub const BYPASS_FLAG_MASK: u8 = 0b_1000_0000;
75 pub const PCC_FLAG_MASK: u8 = 0b_0100_0000;
77 pub const SPARE_MASK: u8 = 0b_0011_0000;
79 pub const OCF_FLAG_MASK: u8 = 0b_0000_1000;
81 pub const VCF_COUNT_LEN_MASK: u8 = 0b_0000_0111;
83
84 pub const TFDZ_RULES_MASK: u8 = 0b_1110_0000;
88 pub const UPID_MASK: u8 = 0b_0001_1111;
90}
91
92use bitmask::*;
93
94#[derive(Debug, Copy, Clone, Eq, PartialEq)]
96#[repr(u8)]
97pub enum TfdzRule {
98 PacketsSpanning = 0,
100 SduStart = 1,
102 SduContinue = 2,
104 OctetStream = 3,
106 StartingSegment = 4,
108 ContinuingSegment = 5,
110 LastSegment = 6,
112 NoSegmentation = 7,
114}
115
116impl TfdzRule {
117 pub fn from_bits(bits: u8) -> Self {
119 match bits & 0x07 {
120 0 => Self::PacketsSpanning,
121 1 => Self::SduStart,
122 2 => Self::SduContinue,
123 3 => Self::OctetStream,
124 4 => Self::StartingSegment,
125 5 => Self::ContinuingSegment,
126 6 => Self::LastSegment,
127 _ => Self::NoSegmentation,
128 }
129 }
130
131 pub fn has_pointer(self) -> bool {
133 matches!(
134 self,
135 Self::PacketsSpanning | Self::SduStart | Self::SduContinue
136 )
137 }
138}
139
140#[derive(Debug, Copy, Clone, Eq, PartialEq)]
144#[repr(u8)]
145pub enum Upid {
146 SpacePackets = 0,
148 EncapsulationPackets = 1,
150 Cop1Commands = 2,
152 CopPCommands = 3,
154 Sdls = 4,
156 IdleData = 30,
158 OnlyIdleData = 31,
160}
161
162#[derive(Debug, Copy, Clone, Eq, PartialEq)]
164pub enum BuildError {
165 InvalidVcid(Vcid),
167 InvalidMapId(u8),
169 InvalidVcfCountLength(u8),
171 BufferTooSmall {
173 required_len: usize,
175 provided_len: usize,
177 },
178 FrameTooLarge {
180 max_len: usize,
182 provided_len: usize,
184 },
185}
186
187#[derive(Debug, Copy, Clone, Eq, PartialEq)]
189pub enum ParseError {
190 TooShortForHeader,
192 LengthMismatch {
194 expected: usize,
196 actual: usize,
198 },
199 InvalidVersion(u8),
201 TruncatedHeader,
203}
204
205#[repr(C, packed)]
221#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, Debug, Copy, Clone)]
222pub struct UslpPrimaryHeaderFixed {
223 id: U32,
226 frame_length: U16,
228 flags: u8,
231}
232
233#[repr(C, packed)]
240#[derive(IntoBytes, FromBytes, Unaligned, KnownLayout, Immutable)]
241pub struct UslpTransferFrame {
242 header: UslpPrimaryHeaderFixed,
243 body: [u8],
244}
245
246#[bon]
247impl UslpTransferFrame {
248 pub const FIXED_HEADER_SIZE: usize = 7;
250
251 pub const MAX_FRAME_SIZE: usize = 65536;
253
254 pub fn parse(bytes: &[u8]) -> Result<&Self, ParseError> {
260 if bytes.len() < Self::FIXED_HEADER_SIZE {
261 return Err(ParseError::TooShortForHeader);
262 }
263
264 let frame =
265 UslpTransferFrame::ref_from_bytes(bytes).map_err(|_| ParseError::TooShortForHeader)?;
266
267 let tfvn = frame.header().tfvn();
268 if tfvn != USLP_TFVN {
269 return Err(ParseError::InvalidVersion(tfvn));
270 }
271
272 if frame.header().eofph() {
273 return Err(ParseError::TruncatedHeader);
274 }
275
276 let expected = frame.header().frame_length() as usize + 1;
277 if bytes.len() != expected {
278 return Err(ParseError::LengthMismatch {
279 expected,
280 actual: bytes.len(),
281 });
282 }
283
284 Ok(frame)
285 }
286
287 pub fn header(&self) -> &UslpPrimaryHeaderFixed {
289 &self.header
290 }
291
292 pub fn header_mut(&mut self) -> &mut UslpPrimaryHeaderFixed {
294 &mut self.header
295 }
296
297 pub fn body(&self) -> &[u8] {
301 &self.body
302 }
303
304 pub fn body_mut(&mut self) -> &mut [u8] {
306 &mut self.body
307 }
308
309 pub fn primary_header_size(&self) -> usize {
311 Self::FIXED_HEADER_SIZE + self.header().vcf_count_length() as usize
312 }
313
314 pub fn vcf_count(&self) -> u64 {
316 let len = self.header().vcf_count_length() as usize;
317 let mut val = 0u64;
318 for &b in &self.body[..len] {
319 val = (val << 8) | b as u64;
320 }
321 val
322 }
323
324 pub fn set_vcf_count(&mut self, count: u64) {
326 let len = self.header().vcf_count_length() as usize;
327 for i in 0..len {
328 let shift = (len - 1 - i) * 8;
329 self.body[i] = (count >> shift) as u8;
330 }
331 }
332
333 pub fn insert_zone(&self, insert_zone_len: usize) -> &[u8] {
338 let start = self.header().vcf_count_length() as usize;
339 &self.body[start..start + insert_zone_len]
340 }
341
342 pub fn insert_zone_mut(&mut self, insert_zone_len: usize) -> &mut [u8] {
344 let start = self.header().vcf_count_length() as usize;
345 &mut self.body[start..start + insert_zone_len]
346 }
347
348 pub fn data_field(&self, insert_zone_len: usize, fecf_present: bool) -> &[u8] {
353 let start = self.header().vcf_count_length() as usize + insert_zone_len;
354 let ocf_len = if self.header().ocf_flag() { 4 } else { 0 };
355 let fecf_len = if fecf_present { 2 } else { 0 };
356 let end = self.body.len() - ocf_len - fecf_len;
357 &self.body[start..end]
358 }
359
360 pub fn data_field_mut(&mut self, insert_zone_len: usize, fecf_present: bool) -> &mut [u8] {
362 let start = self.header().vcf_count_length() as usize + insert_zone_len;
363 let ocf_len = if self.header().ocf_flag() { 4 } else { 0 };
364 let fecf_len = if fecf_present { 2 } else { 0 };
365 let end = self.body.len() - ocf_len - fecf_len;
366 &mut self.body[start..end]
367 }
368
369 pub fn tfdz_rule(&self, insert_zone_len: usize) -> TfdzRule {
371 let off = self.header().vcf_count_length() as usize + insert_zone_len;
372 TfdzRule::from_bits(get_bits_u8(self.body[off], TFDZ_RULES_MASK))
373 }
374
375 pub fn upid(&self, insert_zone_len: usize) -> u8 {
377 let off = self.header().vcf_count_length() as usize + insert_zone_len;
378 get_bits_u8(self.body[off], UPID_MASK)
379 }
380
381 pub fn pointer(&self, insert_zone_len: usize) -> Option<u16> {
386 let rule = self.tfdz_rule(insert_zone_len);
387 if !rule.has_pointer() {
388 return None;
389 }
390 let off = self.header().vcf_count_length() as usize + insert_zone_len + 1;
391 let hi = self.body[off] as u16;
392 let lo = self.body[off + 1] as u16;
393 Some((hi << 8) | lo)
394 }
395
396 pub fn data_zone(&self, insert_zone_len: usize, fecf_present: bool) -> &[u8] {
400 let rule = self.tfdz_rule(insert_zone_len);
401 let tfdf_hdr_len = if rule.has_pointer() { 3 } else { 1 };
402 let start = self.header().vcf_count_length() as usize + insert_zone_len + tfdf_hdr_len;
403 let ocf_len = if self.header().ocf_flag() { 4 } else { 0 };
404 let fecf_len = if fecf_present { 2 } else { 0 };
405 let end = self.body.len() - ocf_len - fecf_len;
406 &self.body[start..end]
407 }
408
409 pub fn ocf(&self, fecf_present: bool) -> Option<&[u8]> {
411 if !self.header().ocf_flag() {
412 return None;
413 }
414 let fecf_len = if fecf_present { 2 } else { 0 };
415 let end = self.body.len() - fecf_len;
416 Some(&self.body[end - 4..end])
417 }
418
419 pub fn fecf(&self, fecf_present: bool) -> Option<&[u8]> {
424 if !fecf_present {
425 return None;
426 }
427 let len = self.body.len();
428 Some(&self.body[len - 2..])
429 }
430
431 pub fn set_tfdf_header(
436 &mut self,
437 insert_zone_len: usize,
438 rule: TfdzRule,
439 upid: u8,
440 pointer: Option<u16>,
441 ) {
442 let off = self.header().vcf_count_length() as usize + insert_zone_len;
443 let mut byte0 = 0u8;
444 set_bits_u8(&mut byte0, TFDZ_RULES_MASK, rule as u8);
445 set_bits_u8(&mut byte0, UPID_MASK, upid);
446 self.body[off] = byte0;
447 if let Some(ptr) = pointer {
448 self.body[off + 1] = (ptr >> 8) as u8;
449 self.body[off + 2] = ptr as u8;
450 }
451 }
452
453 #[builder]
460 pub fn new(
461 buffer: &mut [u8],
462 scid: Scid,
463 vcid: Vcid,
464 #[builder(default)] source_or_dest: bool,
465 #[builder(default)] map_id: u8,
466 #[builder(default)] bypass: bool,
467 #[builder(default)] protocol_control_command: bool,
468 #[builder(default)] ocf_flag: bool,
469 #[builder(default)] vcf_count_length: u8,
470 #[builder(default)] vcf_count: u64,
471 ) -> Result<&mut Self, BuildError> {
472 if vcid.num_bits() > 6 {
473 return Err(BuildError::InvalidVcid(vcid));
474 }
475 if map_id > 15 {
476 return Err(BuildError::InvalidMapId(map_id));
477 }
478 if vcf_count_length > 7 {
479 return Err(BuildError::InvalidVcfCountLength(vcf_count_length));
480 }
481
482 let provided_len = buffer.len();
483 let min_size = Self::FIXED_HEADER_SIZE + vcf_count_length as usize;
484
485 if provided_len < min_size {
486 return Err(BuildError::BufferTooSmall {
487 required_len: min_size,
488 provided_len,
489 });
490 }
491 if provided_len > Self::MAX_FRAME_SIZE {
492 return Err(BuildError::FrameTooLarge {
493 max_len: Self::MAX_FRAME_SIZE,
494 provided_len,
495 });
496 }
497
498 let frame =
499 UslpTransferFrame::mut_from_bytes(buffer).map_err(|_| BuildError::BufferTooSmall {
500 required_len: min_size,
501 provided_len,
502 })?;
503
504 frame.header.id = U32::new(0);
506 frame.header.frame_length = U16::new(0);
507 frame.header.flags = 0;
508
509 frame.header.set_tfvn(USLP_TFVN);
510 frame.header.set_scid(scid);
511 frame.header.set_source_or_dest(source_or_dest);
512 frame.header.set_vcid(vcid);
513 frame.header.set_map_id(map_id);
514 frame.header.set_eofph(false);
515 frame.header.set_frame_length((provided_len - 1) as u16);
516 frame.header.set_bypass(bypass);
517 frame
518 .header
519 .set_protocol_control_command(protocol_control_command);
520 frame.header.set_ocf_flag(ocf_flag);
521 frame.header.set_vcf_count_length(vcf_count_length);
522
523 let vcf_len = vcf_count_length as usize;
525 for i in 0..vcf_len {
526 let shift = (vcf_len - 1 - i) * 8;
527 frame.body[i] = (vcf_count >> shift) as u8;
528 }
529
530 Ok(frame)
531 }
532}
533
534impl UslpPrimaryHeaderFixed {
537 pub fn tfvn(&self) -> u8 {
541 get_bits_u32(self.id, TFVN_MASK) as u8
542 }
543
544 pub fn set_tfvn(&mut self, v: u8) {
546 set_bits_u32(&mut self.id, TFVN_MASK, v as u32);
547 }
548
549 pub fn scid(&self) -> Scid {
551 Scid::new(get_bits_u32(self.id, SCID_MASK) as u32)
552 }
553
554 pub fn set_scid(&mut self, v: Scid) {
556 set_bits_u32(&mut self.id, SCID_MASK, v.get());
557 }
558
559 pub fn source_or_dest(&self) -> bool {
563 get_bits_u32(self.id, SRC_DEST_MASK) != 0
564 }
565
566 pub fn set_source_or_dest(&mut self, v: bool) {
568 set_bits_u32(&mut self.id, SRC_DEST_MASK, v as u32);
569 }
570
571 pub fn vcid(&self) -> Vcid {
573 Vcid::new(get_bits_u32(self.id, VCID_MASK) as u32)
574 }
575
576 pub fn set_vcid(&mut self, v: Vcid) {
578 set_bits_u32(&mut self.id, VCID_MASK, v.get());
579 }
580
581 pub fn map_id(&self) -> u8 {
583 get_bits_u32(self.id, MAP_ID_MASK) as u8
584 }
585
586 pub fn set_map_id(&mut self, v: u8) {
588 set_bits_u32(&mut self.id, MAP_ID_MASK, v as u32);
589 }
590
591 pub fn eofph(&self) -> bool {
596 get_bits_u32(self.id, EOFPH_MASK) != 0
597 }
598
599 pub fn set_eofph(&mut self, v: bool) {
601 set_bits_u32(&mut self.id, EOFPH_MASK, v as u32);
602 }
603
604 pub fn frame_length(&self) -> u16 {
610 self.frame_length.get()
611 }
612
613 pub fn set_frame_length(&mut self, v: u16) {
615 self.frame_length.set(v);
616 }
617
618 pub fn bypass(&self) -> bool {
625 get_bits_u8(self.flags, BYPASS_FLAG_MASK) != 0
626 }
627
628 pub fn set_bypass(&mut self, v: bool) {
630 set_bits_u8(&mut self.flags, BYPASS_FLAG_MASK, v as u8);
631 }
632
633 pub fn protocol_control_command(&self) -> bool {
637 get_bits_u8(self.flags, PCC_FLAG_MASK) != 0
638 }
639
640 pub fn set_protocol_control_command(&mut self, v: bool) {
642 set_bits_u8(&mut self.flags, PCC_FLAG_MASK, v as u8);
643 }
644
645 pub fn ocf_flag(&self) -> bool {
649 get_bits_u8(self.flags, OCF_FLAG_MASK) != 0
650 }
651
652 pub fn set_ocf_flag(&mut self, v: bool) {
654 set_bits_u8(&mut self.flags, OCF_FLAG_MASK, v as u8);
655 }
656
657 pub fn vcf_count_length(&self) -> u8 {
662 get_bits_u8(self.flags, VCF_COUNT_LEN_MASK)
663 }
664
665 pub fn set_vcf_count_length(&mut self, v: u8) {
667 set_bits_u8(&mut self.flags, VCF_COUNT_LEN_MASK, v);
668 }
669}
670
671impl core::fmt::Debug for UslpTransferFrame {
672 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
673 f.debug_struct("UslpTransferFrame")
674 .field("header", &self.header)
675 .field("body_len", &self.body.len())
676 .finish()
677 }
678}
679
680use super::{FrameRead, FrameWrite, PushError};
683
684#[derive(Debug, Clone)]
686pub struct UslpFrameWriterConfig {
687 pub scid: Scid,
689 pub vcid: Vcid,
691 pub map_id: u8,
693 pub bypass: bool,
695 pub protocol_control_command: bool,
697 pub ocf_flag: bool,
699 pub vcf_count_length: u8,
701 pub insert_zone_len: usize,
703 pub tfdz_rule: TfdzRule,
705 pub upid: u8,
707 pub fecf_present: bool,
709 pub max_data_zone_len: usize,
711}
712
713pub struct UslpFrameWriter<const BUF: usize> {
720 config: UslpFrameWriterConfig,
721 vcf_count: u64,
722 data_zone_offset: usize,
723 data_len: usize,
724 buf: [u8; BUF],
725}
726
727impl<const BUF: usize> UslpFrameWriter<BUF> {
728 pub fn new(config: UslpFrameWriterConfig) -> Self {
730 let tfdf_header_len = if config.tfdz_rule.has_pointer() { 3 } else { 1 };
731 let data_zone_offset = UslpTransferFrame::FIXED_HEADER_SIZE
732 + config.vcf_count_length as usize
733 + config.insert_zone_len
734 + tfdf_header_len;
735 Self {
736 config,
737 vcf_count: 0,
738 data_zone_offset,
739 data_len: 0,
740 buf: [0u8; BUF],
741 }
742 }
743
744 fn remaining(&self) -> usize {
745 self.config.max_data_zone_len.saturating_sub(self.data_len)
746 }
747}
748
749impl<const BUF: usize> FrameWrite for UslpFrameWriter<BUF> {
750 type Error = BuildError;
751
752 fn is_empty(&self) -> bool {
753 self.data_len == 0
754 }
755
756 fn push(&mut self, data: &[u8]) -> Result<(), PushError> {
757 if data.len() > self.config.max_data_zone_len {
758 return Err(PushError::TooLarge);
759 }
760 if data.len() > self.remaining() {
761 return Err(PushError::Full);
762 }
763 let off = self.data_zone_offset + self.data_len;
764 self.buf[off..off + data.len()].copy_from_slice(data);
765 self.data_len += data.len();
766 Ok(())
767 }
768
769 fn finish(&mut self) -> Result<&[u8], BuildError> {
770 let ocf_len = if self.config.ocf_flag { 4 } else { 0 };
771 let fecf_len = if self.config.fecf_present { 2 } else { 0 };
772 let total = self.data_zone_offset + self.data_len + ocf_len + fecf_len;
773
774 let vcf_count = self.vcf_count;
775 self.vcf_count = self.vcf_count.wrapping_add(1);
776
777 UslpTransferFrame::builder()
781 .buffer(&mut self.buf[..total])
782 .scid(self.config.scid)
783 .vcid(self.config.vcid)
784 .map_id(self.config.map_id)
785 .bypass(self.config.bypass)
786 .protocol_control_command(self.config.protocol_control_command)
787 .ocf_flag(self.config.ocf_flag)
788 .vcf_count_length(self.config.vcf_count_length)
789 .vcf_count(vcf_count)
790 .build()?;
791
792 let frame = UslpTransferFrame::mut_from_bytes(&mut self.buf[..total]).unwrap();
794 frame.set_tfdf_header(
795 self.config.insert_zone_len,
796 self.config.tfdz_rule,
797 self.config.upid,
798 if self.config.tfdz_rule.has_pointer() {
799 Some(0)
800 } else {
801 None
802 },
803 );
804
805 self.data_len = 0;
806 Ok(&self.buf[..total])
807 }
808}
809
810pub struct UslpFrameReader<const BUF: usize> {
818 insert_zone_len: usize,
819 fecf_present: bool,
820 buf: [u8; BUF],
821 data_start: usize,
822 data_end: usize,
823}
824
825impl<const BUF: usize> UslpFrameReader<BUF> {
826 pub fn new(insert_zone_len: usize, fecf_present: bool) -> Self {
828 Self {
829 insert_zone_len,
830 fecf_present,
831 buf: [0u8; BUF],
832 data_start: 0,
833 data_end: 0,
834 }
835 }
836}
837
838impl<const BUF: usize> FrameRead for UslpFrameReader<BUF> {
839 type Error = ParseError;
840
841 fn buffer_mut(&mut self) -> &mut [u8] {
842 &mut self.buf
843 }
844
845 fn feed(&mut self, len: usize) -> Result<(), ParseError> {
846 let frame = UslpTransferFrame::parse(&self.buf[..len])?;
847 let rule = frame.tfdz_rule(self.insert_zone_len);
848 let tfdf_hdr_len = if rule.has_pointer() { 3 } else { 1 };
849 let header_overhead = UslpTransferFrame::FIXED_HEADER_SIZE
850 + frame.header().vcf_count_length() as usize
851 + self.insert_zone_len
852 + tfdf_hdr_len;
853 let ocf_len = if frame.header().ocf_flag() { 4 } else { 0 };
854 let fecf_len = if self.fecf_present { 2 } else { 0 };
855 self.data_start = header_overhead;
856 self.data_end = len - ocf_len - fecf_len;
857 Ok(())
858 }
859
860 fn data_field(&self) -> &[u8] {
861 &self.buf[self.data_start..self.data_end]
862 }
863}
864
865#[cfg(test)]
866mod tests {
867 use super::*;
868 use crate::ids::{Scid, Vcid};
869
870 #[test]
871 fn build_and_parse_basic_frame() {
872 let mut buf = [0u8; 32];
873 let frame = UslpTransferFrame::builder()
874 .buffer(&mut buf)
875 .scid(Scid::new(42))
876 .vcid(Vcid::new(1))
877 .build()
878 .unwrap();
879
880 assert_eq!(frame.header().tfvn(), USLP_TFVN);
881 assert_eq!(frame.header().scid(), Scid::new(42));
882 assert_eq!(frame.header().vcid(), Vcid::new(1));
883 assert_eq!(frame.header().map_id(), 0);
884 assert!(!frame.header().source_or_dest());
885 assert!(!frame.header().eofph());
886 assert!(!frame.header().bypass());
887 assert!(!frame.header().protocol_control_command());
888 assert!(!frame.header().ocf_flag());
889 assert_eq!(frame.header().vcf_count_length(), 0);
890 assert_eq!(frame.header().frame_length(), 31);
891 }
892
893 #[test]
894 fn parse_validates_tfvn() {
895 let mut buf = [0u8; 16];
896 UslpTransferFrame::builder()
898 .buffer(&mut buf)
899 .scid(Scid::new(0))
900 .vcid(Vcid::new(0))
901 .build()
902 .unwrap();
903 buf[0] = 0x00; let err = UslpTransferFrame::parse(&buf).unwrap_err();
905 assert_eq!(err, ParseError::InvalidVersion(0));
906 }
907
908 #[test]
909 fn parse_validates_length() {
910 let mut buf = [0u8; 16];
911 UslpTransferFrame::builder()
912 .buffer(&mut buf)
913 .scid(Scid::new(0))
914 .vcid(Vcid::new(0))
915 .build()
916 .unwrap();
917 let err = UslpTransferFrame::parse(&buf[..12]).unwrap_err();
919 assert!(matches!(err, ParseError::LengthMismatch { .. }));
920 }
921
922 #[test]
923 fn roundtrip_with_vcf_count() {
924 let mut buf = [0u8; 64];
925 let frame = UslpTransferFrame::builder()
926 .buffer(&mut buf)
927 .scid(Scid::new(1000))
928 .vcid(Vcid::new(5))
929 .map_id(3)
930 .bypass(true)
931 .vcf_count_length(2)
932 .vcf_count(1234)
933 .build()
934 .unwrap();
935
936 assert_eq!(frame.header().scid(), Scid::new(1000));
937 assert_eq!(frame.header().vcid(), Vcid::new(5));
938 assert_eq!(frame.header().map_id(), 3);
939 assert!(frame.header().bypass());
940 assert_eq!(frame.header().vcf_count_length(), 2);
941 assert_eq!(frame.vcf_count(), 1234);
942 assert_eq!(frame.primary_header_size(), 9);
943 }
944
945 #[test]
946 fn roundtrip_parse() {
947 let mut buf = [0u8; 32];
948 UslpTransferFrame::builder()
949 .buffer(&mut buf)
950 .scid(Scid::new(500))
951 .vcid(Vcid::new(7))
952 .source_or_dest(true)
953 .ocf_flag(true)
954 .build()
955 .unwrap();
956
957 let frame = UslpTransferFrame::parse(&buf).unwrap();
958 assert_eq!(frame.header().scid(), Scid::new(500));
959 assert_eq!(frame.header().vcid(), Vcid::new(7));
960 assert!(frame.header().source_or_dest());
961 assert!(frame.header().ocf_flag());
962 }
963
964 #[test]
965 fn tfdf_header_roundtrip() {
966 let mut buf = [0u8; 32];
967 let frame = UslpTransferFrame::builder()
968 .buffer(&mut buf)
969 .scid(Scid::new(0))
970 .vcid(Vcid::new(0))
971 .build()
972 .unwrap();
973
974 frame.set_tfdf_header(0, TfdzRule::NoSegmentation, Upid::SpacePackets as u8, None);
975
976 assert_eq!(frame.tfdz_rule(0), TfdzRule::NoSegmentation);
977 assert_eq!(frame.upid(0), 0);
978 assert_eq!(frame.pointer(0), None);
979 }
980
981 #[test]
982 fn tfdf_header_with_pointer() {
983 let mut buf = [0u8; 32];
984 let frame = UslpTransferFrame::builder()
985 .buffer(&mut buf)
986 .scid(Scid::new(0))
987 .vcid(Vcid::new(0))
988 .build()
989 .unwrap();
990
991 frame.set_tfdf_header(
992 0,
993 TfdzRule::PacketsSpanning,
994 Upid::SpacePackets as u8,
995 Some(0x0100),
996 );
997
998 assert_eq!(frame.tfdz_rule(0), TfdzRule::PacketsSpanning);
999 assert_eq!(frame.pointer(0), Some(0x0100));
1000 }
1001
1002 #[test]
1003 fn invalid_vcid_rejected() {
1004 let mut buf = [0u8; 32];
1005 let err = UslpTransferFrame::builder()
1006 .buffer(&mut buf)
1007 .scid(Scid::new(0))
1008 .vcid(Vcid::new(64))
1009 .build()
1010 .unwrap_err();
1011 assert_eq!(err, BuildError::InvalidVcid(Vcid::new(64)));
1012 }
1013
1014 #[test]
1015 fn tfdz_rule_from_bits() {
1016 for i in 0..=7u8 {
1017 let rule = TfdzRule::from_bits(i);
1018 assert_eq!(rule as u8, i);
1019 }
1020 }
1021
1022 #[test]
1023 fn tfdz_rule_has_pointer() {
1024 assert!(TfdzRule::PacketsSpanning.has_pointer());
1025 assert!(TfdzRule::SduStart.has_pointer());
1026 assert!(TfdzRule::SduContinue.has_pointer());
1027 assert!(!TfdzRule::OctetStream.has_pointer());
1028 assert!(!TfdzRule::StartingSegment.has_pointer());
1029 assert!(!TfdzRule::ContinuingSegment.has_pointer());
1030 assert!(!TfdzRule::LastSegment.has_pointer());
1031 assert!(!TfdzRule::NoSegmentation.has_pointer());
1032 }
1033
1034 #[test]
1035 fn max_scid() {
1036 let mut buf = [0u8; 16];
1037 let frame = UslpTransferFrame::builder()
1038 .buffer(&mut buf)
1039 .scid(Scid::new(0xFFFF))
1040 .vcid(Vcid::new(0))
1041 .build()
1042 .unwrap();
1043 assert_eq!(frame.header().scid(), Scid::new(0xFFFF));
1044 }
1045}