Skip to main content

leodos_protocols/datalink/spp/
encapsulation.rs

1//! CCSDS Encapsulation Packet Protocol (CCSDS 133.1-B-3)
2//!
3//! Encapsulation Packets provide a mechanism to carry non-CCSDS
4//! protocol data (e.g., IP datagrams) over CCSDS space links. They
5//! share the same Packet Version Number (PVN = 7, binary '111') space
6//! as Space Packets (PVN = 0) but use a different header format.
7//!
8//! # Header Layout
9//!
10//! ```text
11//! ┌──────────────────────────────────────────────────────┐
12//! │ Packet Version Number (3 bits) = '111'               │
13//! │ Protocol ID (4 bits)                                 │
14//! │ Length of Length (2 bits)                             │
15//! │ User Defined Field (4 bits)                          │
16//! │ Protocol ID Extension (4 bits)                       │
17//! │ CCSDS-defined field (1 bit)                          │
18//! │ Packet Length (variable: 0, 1, 2, or 4 bytes)        │
19//! └──────────────────────────────────────────────────────┘
20//! ```
21//!
22//! The first two bytes are always present. The Packet Length field
23//! is 0-4 bytes depending on the Length of Length field.
24
25use zerocopy::FromBytes;
26use zerocopy::Immutable;
27use zerocopy::IntoBytes;
28use zerocopy::KnownLayout;
29use zerocopy::Unaligned;
30use zerocopy::byteorder::network_endian::U16;
31
32use crate::utils::get_bits_u16;
33use crate::utils::set_bits_u16;
34
35/// The 2-byte mandatory portion of an Encapsulation Packet header.
36#[repr(C)]
37#[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, Debug, Copy, Clone)]
38pub struct EncapsulationHeader {
39    /// PVN(3) | Protocol ID(4) | Length of Length(2) |
40    /// User Defined(4) | Protocol ID Extension(4) | CCSDS Defined(1).
41    fields: U16,
42}
43
44/// Bitmasks for the 16-bit encapsulation header.
45#[rustfmt::skip]
46pub mod bitmask {
47    /// Packet Version Number (3 bits) — always 0b111 = 7.
48    pub const PVN_MASK: u16          = 0b_1110_0000_0000_0000;
49    /// Protocol ID (4 bits).
50    pub const PROTOCOL_ID_MASK: u16  = 0b_0001_1110_0000_0000;
51    /// Length of Length (2 bits).
52    pub const LEN_OF_LEN_MASK: u16   = 0b_0000_0001_1000_0000;
53    /// User Defined Field (4 bits).
54    pub const USER_DEF_MASK: u16     = 0b_0000_0000_0111_1000;
55    /// Protocol ID Extension (4 bits).
56    pub const PID_EXT_MASK: u16      = 0b_0000_0000_0000_0111_u16 << 1;
57    /// CCSDS Defined Field (1 bit).
58    pub const CCSDS_DEF_MASK: u16    = 0b_0000_0000_0000_0001;
59}
60
61use bitmask::*;
62
63/// Well-known Protocol ID values (CCSDS 133.1-B-3, Table 4-1).
64#[derive(Debug, Copy, Clone, Eq, PartialEq)]
65#[repr(u8)]
66pub enum ProtocolId {
67    /// Idle packet (all zeros payload).
68    Idle = 0b0000,
69    /// Internet Protocol Extension (IPE).
70    Ipe = 0b0001,
71    /// CCSDS-defined protocol — type in extension field.
72    CcsdsDefined = 0b0010,
73    /// User-defined protocol (0b0111 = mission-specific).
74    UserDefined = 0b0111,
75    /// Internet Protocol version 4.
76    Ipv4 = 0b1000,
77    /// Internet Protocol version 6.
78    Ipv6 = 0b1001,
79}
80
81/// Errors for Encapsulation Packet operations.
82#[derive(Debug, Copy, Clone, Eq, PartialEq, thiserror::Error)]
83pub enum Error {
84    /// Buffer too short for the header.
85    #[error("buffer too short: required {required} bytes, provided {provided} bytes")]
86    BufferTooShort {
87        /// Minimum bytes needed.
88        required: usize,
89        /// Actual bytes available.
90        provided: usize,
91    },
92    /// Invalid Packet Version Number (not 0b111).
93    #[error("invalid Packet Version Number: expected 0b111, got {0:#05b}")]
94    InvalidPvn(u8),
95}
96
97/// Encapsulation Packet Version Number (binary '111' = 7).
98pub const ENCAP_PVN: u8 = 0b111;
99
100impl EncapsulationHeader {
101    /// Minimum header size: the 2-byte mandatory portion.
102    pub const MIN_SIZE: usize = 2;
103
104    /// Returns the 3-bit Packet Version Number.
105    pub fn pvn(&self) -> u8 {
106        get_bits_u16(self.fields, PVN_MASK) as u8
107    }
108    /// Sets the Packet Version Number.
109    pub fn set_pvn(&mut self, pvn: u8) {
110        set_bits_u16(&mut self.fields, PVN_MASK, pvn as u16);
111    }
112
113    /// Returns the 4-bit Protocol ID.
114    pub fn protocol_id(&self) -> u8 {
115        get_bits_u16(self.fields, PROTOCOL_ID_MASK) as u8
116    }
117    /// Sets the 4-bit Protocol ID.
118    pub fn set_protocol_id(&mut self, pid: u8) {
119        set_bits_u16(&mut self.fields, PROTOCOL_ID_MASK, pid as u16);
120    }
121
122    /// Returns the 2-bit Length of Length field.
123    ///
124    /// This determines how many bytes follow for the packet length:
125    /// - 0b00: 0 bytes (length is implicit/undefined)
126    /// - 0b01: 1 byte (max 255)
127    /// - 0b10: 2 bytes (max 65535)
128    /// - 0b11: 4 bytes (max 4294967295)
129    pub fn len_of_len(&self) -> u8 {
130        get_bits_u16(self.fields, LEN_OF_LEN_MASK) as u8
131    }
132    /// Sets the 2-bit Length of Length field.
133    pub fn set_len_of_len(&mut self, lol: u8) {
134        set_bits_u16(&mut self.fields, LEN_OF_LEN_MASK, lol as u16);
135    }
136
137    /// Returns the 4-bit User Defined field.
138    pub fn user_defined(&self) -> u8 {
139        get_bits_u16(self.fields, USER_DEF_MASK) as u8
140    }
141    /// Sets the 4-bit User Defined field.
142    pub fn set_user_defined(&mut self, ud: u8) {
143        set_bits_u16(&mut self.fields, USER_DEF_MASK, ud as u16);
144    }
145
146    /// Returns the 4-bit Protocol ID Extension.
147    pub fn protocol_id_extension(&self) -> u8 {
148        get_bits_u16(self.fields, PID_EXT_MASK) as u8
149    }
150    /// Sets the 4-bit Protocol ID Extension.
151    pub fn set_protocol_id_extension(&mut self, ext: u8) {
152        set_bits_u16(&mut self.fields, PID_EXT_MASK, ext as u16);
153    }
154
155    /// Returns the 1-bit CCSDS Defined field.
156    pub fn ccsds_defined(&self) -> bool {
157        get_bits_u16(self.fields, CCSDS_DEF_MASK) != 0
158    }
159    /// Sets the 1-bit CCSDS Defined field.
160    pub fn set_ccsds_defined(&mut self, val: bool) {
161        set_bits_u16(&mut self.fields, CCSDS_DEF_MASK, u16::from(val));
162    }
163
164    /// Returns the number of bytes used for the packet length field.
165    pub fn packet_length_bytes(&self) -> usize {
166        match self.len_of_len() {
167            0b00 => 0,
168            0b01 => 1,
169            0b10 => 2,
170            _ => 4,
171        }
172    }
173
174    /// Returns the total header size (mandatory 2 bytes + length bytes).
175    pub fn total_header_size(&self) -> usize {
176        Self::MIN_SIZE + self.packet_length_bytes()
177    }
178
179    /// Parses from a byte slice.
180    pub fn parse(bytes: &[u8]) -> Result<&Self, Error> {
181        if bytes.len() < Self::MIN_SIZE {
182            return Err(Error::BufferTooShort {
183                required: Self::MIN_SIZE,
184                provided: bytes.len(),
185            });
186        }
187        let (hdr, _) = Self::ref_from_prefix(bytes).unwrap();
188        if hdr.pvn() != ENCAP_PVN {
189            return Err(Error::InvalidPvn(hdr.pvn()));
190        }
191        Ok(hdr)
192    }
193}
194
195/// Reads the variable-length packet length from the bytes following
196/// the 2-byte mandatory header.
197///
198/// `len_of_len` is the value from the header's Length of Length field.
199/// `bytes` should start at the first byte after the mandatory header.
200pub fn read_packet_length(len_of_len: u8, bytes: &[u8]) -> Result<Option<u32>, Error> {
201    match len_of_len {
202        0b00 => Ok(None),
203        0b01 => {
204            if bytes.is_empty() {
205                return Err(Error::BufferTooShort {
206                    required: 1,
207                    provided: 0,
208                });
209            }
210            Ok(Some(bytes[0] as u32))
211        }
212        0b10 => {
213            if bytes.len() < 2 {
214                return Err(Error::BufferTooShort {
215                    required: 2,
216                    provided: bytes.len(),
217                });
218            }
219            Ok(Some(u16::from_be_bytes([bytes[0], bytes[1]]) as u32))
220        }
221        _ => {
222            if bytes.len() < 4 {
223                return Err(Error::BufferTooShort {
224                    required: 4,
225                    provided: bytes.len(),
226                });
227            }
228            Ok(Some(u32::from_be_bytes([
229                bytes[0], bytes[1], bytes[2], bytes[3],
230            ])))
231        }
232    }
233}
234
235/// Writes the variable-length packet length after the mandatory header.
236///
237/// Returns the number of bytes written (0, 1, 2, or 4).
238pub fn write_packet_length(len_of_len: u8, length: u32, bytes: &mut [u8]) -> Result<usize, Error> {
239    match len_of_len {
240        0b00 => Ok(0),
241        0b01 => {
242            if bytes.is_empty() {
243                return Err(Error::BufferTooShort {
244                    required: 1,
245                    provided: 0,
246                });
247            }
248            bytes[0] = length as u8;
249            Ok(1)
250        }
251        0b10 => {
252            if bytes.len() < 2 {
253                return Err(Error::BufferTooShort {
254                    required: 2,
255                    provided: bytes.len(),
256                });
257            }
258            let b = (length as u16).to_be_bytes();
259            bytes[0] = b[0];
260            bytes[1] = b[1];
261            Ok(2)
262        }
263        _ => {
264            if bytes.len() < 4 {
265                return Err(Error::BufferTooShort {
266                    required: 4,
267                    provided: bytes.len(),
268                });
269            }
270            let b = length.to_be_bytes();
271            bytes[..4].copy_from_slice(&b);
272            Ok(4)
273        }
274    }
275}
276
277#[cfg(test)]
278mod tests {
279    use super::*;
280
281    #[test]
282    fn header_pvn_is_111() {
283        let mut buf = [0u8; 2];
284        let hdr = EncapsulationHeader::mut_from_bytes(&mut buf).unwrap();
285        hdr.set_pvn(ENCAP_PVN);
286        assert_eq!(hdr.pvn(), 0b111);
287        // Top 3 bits of first byte should be 0b111 = 0xE0
288        assert_eq!(buf[0] & 0xE0, 0xE0);
289    }
290
291    #[test]
292    fn protocol_id_roundtrip() {
293        let mut buf = [0u8; 2];
294        let hdr = EncapsulationHeader::mut_from_bytes(&mut buf).unwrap();
295        hdr.set_pvn(ENCAP_PVN);
296        hdr.set_protocol_id(ProtocolId::Ipv4 as u8);
297        assert_eq!(hdr.protocol_id(), ProtocolId::Ipv4 as u8);
298    }
299
300    #[test]
301    fn len_of_len_values() {
302        for lol in 0..=3u8 {
303            let mut buf = [0u8; 2];
304            let hdr = EncapsulationHeader::mut_from_bytes(&mut buf).unwrap();
305            hdr.set_pvn(ENCAP_PVN);
306            hdr.set_len_of_len(lol);
307            assert_eq!(hdr.len_of_len(), lol);
308            let expected_bytes = match lol {
309                0 => 0,
310                1 => 1,
311                2 => 2,
312                _ => 4,
313            };
314            assert_eq!(hdr.packet_length_bytes(), expected_bytes);
315        }
316    }
317
318    #[test]
319    fn user_defined_field() {
320        let mut buf = [0u8; 2];
321        let hdr = EncapsulationHeader::mut_from_bytes(&mut buf).unwrap();
322        hdr.set_pvn(ENCAP_PVN);
323        hdr.set_user_defined(0x0F);
324        assert_eq!(hdr.user_defined(), 0x0F);
325    }
326
327    #[test]
328    fn parse_validates_pvn() {
329        let buf = [0u8; 2]; // PVN = 0
330        let err = EncapsulationHeader::parse(&buf);
331        assert!(matches!(err, Err(Error::InvalidPvn(0))));
332    }
333
334    #[test]
335    fn parse_valid() {
336        let mut buf = [0u8; 2];
337        let hdr = EncapsulationHeader::mut_from_bytes(&mut buf).unwrap();
338        hdr.set_pvn(ENCAP_PVN);
339        hdr.set_protocol_id(ProtocolId::Ipv6 as u8);
340        hdr.set_len_of_len(0b10);
341
342        let parsed = EncapsulationHeader::parse(&buf).unwrap();
343        assert_eq!(parsed.pvn(), ENCAP_PVN);
344        assert_eq!(parsed.protocol_id(), ProtocolId::Ipv6 as u8);
345        assert_eq!(parsed.len_of_len(), 0b10);
346    }
347
348    #[test]
349    fn read_write_packet_length_1byte() {
350        let mut buf = [0u8; 4];
351        let n = write_packet_length(0b01, 200, &mut buf).unwrap();
352        assert_eq!(n, 1);
353        let len = read_packet_length(0b01, &buf).unwrap();
354        assert_eq!(len, Some(200));
355    }
356
357    #[test]
358    fn read_write_packet_length_2byte() {
359        let mut buf = [0u8; 4];
360        let n = write_packet_length(0b10, 50000, &mut buf).unwrap();
361        assert_eq!(n, 2);
362        let len = read_packet_length(0b10, &buf).unwrap();
363        assert_eq!(len, Some(50000));
364    }
365
366    #[test]
367    fn read_write_packet_length_4byte() {
368        let mut buf = [0u8; 4];
369        let n = write_packet_length(0b11, 1_000_000, &mut buf).unwrap();
370        assert_eq!(n, 4);
371        let len = read_packet_length(0b11, &buf).unwrap();
372        assert_eq!(len, Some(1_000_000));
373    }
374
375    #[test]
376    fn packet_length_zero_means_none() {
377        let buf = [0u8; 4];
378        let len = read_packet_length(0b00, &buf).unwrap();
379        assert_eq!(len, None);
380    }
381
382    #[test]
383    fn total_header_size() {
384        let mut buf = [0u8; 2];
385        let hdr = EncapsulationHeader::mut_from_bytes(&mut buf).unwrap();
386
387        hdr.set_len_of_len(0b00);
388        assert_eq!(hdr.total_header_size(), 2);
389
390        hdr.set_len_of_len(0b01);
391        assert_eq!(hdr.total_header_size(), 3);
392
393        hdr.set_len_of_len(0b10);
394        assert_eq!(hdr.total_header_size(), 4);
395
396        hdr.set_len_of_len(0b11);
397        assert_eq!(hdr.total_header_size(), 6);
398    }
399}