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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy