Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/link/
linux_sll_header.rs

1use crate::{err, ArpHardwareId, LinuxSllHeaderSlice, LinuxSllPacketType, LinuxSllProtocolType};
2
3/// Linux Cooked Capture v1 (SLL) Header
4#[derive(Clone, Debug, Eq, PartialEq)]
5pub struct LinuxSllHeader {
6    /// Type of the captured packet
7    pub packet_type: LinuxSllPacketType,
8    /// ARPHRD_ value for the link-layer device type
9    pub arp_hrd_type: ArpHardwareId,
10    /// The size of the address that is valid
11    pub sender_address_valid_length: u16,
12    /// The link-layer address of the sender of the packet, with the meaningful
13    /// bytes specified by `sender_address_valid_length`. If the original is
14    /// larger, the value on the packet is truncated to the first 8 bytes. If
15    /// the original is smaller, the remaining bytes will be filled with 0s.
16    pub sender_address: [u8; 8],
17    /// The protocol type of the encapsulated packet
18    pub protocol_type: LinuxSllProtocolType,
19}
20
21impl LinuxSllHeader {
22    /// Serialized size of an SLL header in bytes/octets.
23    pub const LEN: usize = 16;
24
25    /// Read an SLL header from a slice and return the header & unused parts of the slice.
26    #[inline]
27    pub fn from_slice(
28        slice: &[u8],
29    ) -> Result<(LinuxSllHeader, &[u8]), err::linux_sll::HeaderSliceError> {
30        Ok((
31            LinuxSllHeaderSlice::from_slice(slice)?.to_header(),
32            &slice[LinuxSllHeader::LEN..],
33        ))
34    }
35
36    /// Read an SLL header from a static sized byte array.
37    #[inline]
38    pub fn from_bytes(bytes: [u8; 16]) -> Result<LinuxSllHeader, err::linux_sll::HeaderError> {
39        let packet_type = LinuxSllPacketType::try_from(u16::from_be_bytes([bytes[0], bytes[1]]))?;
40        let arp_hrd_type = ArpHardwareId::from(u16::from_be_bytes([bytes[2], bytes[3]]));
41        let sender_address_valid_length = u16::from_be_bytes([bytes[4], bytes[5]]);
42        let sender_address = [
43            bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13],
44        ];
45        let protocol_type = LinuxSllProtocolType::try_from((
46            arp_hrd_type,
47            u16::from_be_bytes([bytes[14], bytes[15]]),
48        ))?;
49
50        Ok(LinuxSllHeader {
51            packet_type,
52            arp_hrd_type,
53            sender_address_valid_length,
54            sender_address,
55            protocol_type,
56        })
57    }
58
59    /// Reads an SLL header from the current position of the read argument.
60    #[cfg(feature = "std")]
61    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
62    pub fn read<T: std::io::Read + std::io::Seek + Sized>(
63        reader: &mut T,
64    ) -> Result<LinuxSllHeader, err::ReadError> {
65        let buffer = {
66            let mut buffer = [0; LinuxSllHeader::LEN];
67            reader.read_exact(&mut buffer)?;
68            buffer
69        };
70
71        Ok(
72            // SAFETY: Safe as the buffer contains exactly the needed LinuxSllHeader::LEN bytes.
73            unsafe { LinuxSllHeaderSlice::from_slice_unchecked(&buffer) }.to_header(),
74        )
75    }
76
77    /// Serialize the header to a given slice. Returns the unused part of the slice.
78    pub fn write_to_slice<'a>(
79        &self,
80        slice: &'a mut [u8],
81    ) -> Result<&'a mut [u8], err::SliceWriteSpaceError> {
82        // length check
83        if slice.len() < LinuxSllHeader::LEN {
84            Err(err::SliceWriteSpaceError {
85                required_len: LinuxSllHeader::LEN,
86                len: slice.len(),
87                layer: err::Layer::LinuxSllHeader,
88                layer_start_offset: 0,
89            })
90        } else {
91            slice[..LinuxSllHeader::LEN].copy_from_slice(&self.to_bytes());
92            Ok(&mut slice[LinuxSllHeader::LEN..])
93        }
94    }
95
96    /// Writes a given Sll header to the current position of the write argument.
97    #[cfg(feature = "std")]
98    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
99    #[inline]
100    pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
101        writer.write_all(&self.to_bytes())
102    }
103
104    /// Length of the serialized header in bytes.
105    #[inline]
106    pub fn header_len(&self) -> usize {
107        Self::LEN
108    }
109
110    /// Returns the serialized form of the header as a statically
111    /// sized byte array.
112    #[inline]
113    pub fn to_bytes(&self) -> [u8; Self::LEN] {
114        let packet_type_be = u16::from(self.packet_type).to_be_bytes();
115        let arp_hrd_type_be = u16::from(self.arp_hrd_type).to_be_bytes();
116        let sender_address_valid_length_be = self.sender_address_valid_length.to_be_bytes();
117        let sender_address_be = self.sender_address;
118        let protocol_type_be = u16::from(self.protocol_type).to_be_bytes();
119
120        [
121            packet_type_be[0],
122            packet_type_be[1],
123            arp_hrd_type_be[0],
124            arp_hrd_type_be[1],
125            sender_address_valid_length_be[0],
126            sender_address_valid_length_be[1],
127            sender_address_be[0],
128            sender_address_be[1],
129            sender_address_be[2],
130            sender_address_be[3],
131            sender_address_be[4],
132            sender_address_be[5],
133            sender_address_be[6],
134            sender_address_be[7],
135            protocol_type_be[0],
136            protocol_type_be[1],
137        ]
138    }
139}
140
141#[cfg(test)]
142mod test {
143    use super::*;
144    use crate::{test_gens::*, LenSource};
145    use alloc::{format, vec::Vec};
146    use proptest::prelude::*;
147    use std::io::{Cursor, ErrorKind};
148
149    proptest! {
150        #[test]
151        fn from_slice(
152            input in linux_sll_any(),
153            dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
154        ) {
155            // serialize
156            let mut buffer: Vec<u8> = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len());
157            input.write(&mut buffer).unwrap();
158            buffer.extend(&dummy_data[..]);
159
160            // calls with a valid result
161            {
162                let (result, rest) = LinuxSllHeader::from_slice(&buffer[..]).unwrap();
163                assert_eq!(input, result);
164                assert_eq!(&buffer[16..], rest);
165            }
166
167            // call with not enough data in the slice
168            for len in 0..=13 {
169                assert_eq!(
170                    LinuxSllHeader::from_slice(&buffer[..len]).unwrap_err(),
171                    err::linux_sll::HeaderSliceError::Len(err::LenError{
172                        required_len: LinuxSllHeader::LEN,
173                        len: len,
174                        len_source: LenSource::Slice,
175                        layer: err::Layer::LinuxSllHeader,
176                        layer_start_offset: 0,
177                    })
178                );
179            }
180        }
181    }
182
183    proptest! {
184        #[test]
185        fn from_bytes(input in linux_sll_any()) {
186            assert_eq!(
187                input,
188                LinuxSllHeader::from_bytes(input.to_bytes()).unwrap()
189            );
190        }
191    }
192
193    proptest! {
194        #[test]
195        fn read(
196            input in linux_sll_any(),
197            dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
198        ) {
199            // normal read
200            let mut buffer = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len());
201            input.write(&mut buffer).unwrap();
202            buffer.extend(&dummy_data[..]);
203
204            // calls with a valid result
205            {
206                let mut cursor = Cursor::new(&buffer);
207                let result = LinuxSllHeader::read(&mut cursor).unwrap();
208                assert_eq!(input, result);
209                assert_eq!(cursor.position(), u64::try_from(LinuxSllHeader::LEN).unwrap());
210            }
211
212            // unexpected eof
213            for len in 0..=13 {
214                let mut cursor = Cursor::new(&buffer[0..len]);
215                assert_eq!(
216                    LinuxSllHeader::read(&mut cursor)
217                    .unwrap_err()
218                    .io().unwrap()
219                    .kind(),
220                    ErrorKind::UnexpectedEof
221                );
222            }
223        }
224    }
225
226    proptest! {
227        #[test]
228        fn write_to_slice(input in linux_sll_any()) {
229            // normal write
230            {
231                let mut buffer: [u8;LinuxSllHeader::LEN] = [0;LinuxSllHeader::LEN];
232                input.write_to_slice(&mut buffer).unwrap();
233                assert_eq!(buffer, input.to_bytes());
234            }
235            // len to small
236            for len in 0..14 {
237                let mut buffer: [u8;LinuxSllHeader::LEN] = [0;LinuxSllHeader::LEN];
238                assert_eq!(
239                    err::SliceWriteSpaceError {
240                        required_len: LinuxSllHeader::LEN,
241                        len,
242                        layer: err::Layer::LinuxSllHeader,
243                        layer_start_offset: 0,
244                    },
245                    input.write_to_slice(&mut buffer[..len]).unwrap_err()
246                );
247            }
248        }
249    }
250
251    proptest! {
252        #[test]
253        fn write(input in linux_sll_any()) {
254            // successful write
255            {
256                let mut buffer: Vec<u8> = Vec::with_capacity(LinuxSllHeader::LEN);
257                input.write(&mut buffer).unwrap();
258                assert_eq!(&buffer[..], &input.to_bytes());
259            }
260
261            // not enough memory for write (unexpected eof)
262            for len in 0..8 {
263                let mut buffer = [0u8;8];
264                let mut writer = Cursor::new(&mut buffer[..len]);
265                assert!(input.write(&mut writer).is_err());
266            }
267        }
268    }
269
270    proptest! {
271        #[test]
272        fn header_len(input in linux_sll_any()) {
273            assert_eq!(input.header_len(), LinuxSllHeader::LEN);
274        }
275    }
276
277    proptest! {
278        #[test]
279        fn to_bytes(input in linux_sll_any()) {
280            let packet_type_be = u16::from(input.packet_type).to_be_bytes();
281            let arp_hrd_type_be = u16::from(input.arp_hrd_type).to_be_bytes();
282            let sender_address_valid_length_be = input.sender_address_valid_length.to_be_bytes();
283            let sender_address_be = input.sender_address;
284            let protocol_type_be = u16::from(input.protocol_type).to_be_bytes();
285
286            assert_eq!(
287                input.to_bytes(),
288                [
289                    packet_type_be[0],
290                    packet_type_be[1],
291                    arp_hrd_type_be[0],
292                    arp_hrd_type_be[1],
293                    sender_address_valid_length_be[0],
294                    sender_address_valid_length_be[1],
295                    sender_address_be[0],
296                    sender_address_be[1],
297                    sender_address_be[2],
298                    sender_address_be[3],
299                    sender_address_be[4],
300                    sender_address_be[5],
301                    sender_address_be[6],
302                    sender_address_be[7],
303                    protocol_type_be[0],
304                    protocol_type_be[1],
305                ]
306            );
307        }
308    }
309
310    proptest! {
311        #[test]
312        fn clone_eq(input in linux_sll_any()) {
313            assert_eq!(input, input.clone());
314        }
315    }
316
317    proptest! {
318        #[test]
319        fn dbg(input in linux_sll_any()) {
320            assert_eq!(
321                &format!(
322                    "LinuxSllHeader {{ packet_type: {:?}, arp_hrd_type: {:?}, sender_address_valid_length: {:?}, sender_address: {:?}, protocol_type: {:?} }}",
323                    input.packet_type,
324                    input.arp_hrd_type,
325                    input.sender_address_valid_length,
326                    input.sender_address,
327                    input.protocol_type,
328                ),
329                &format!("{:?}", input)
330            );
331        }
332    }
333}