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

etherparse/link/
linux_sll_header_slice.rs

1use crate::*;
2use core::{cmp::min, slice::from_raw_parts};
3
4///A slice containing an Linux Cooked Capture (SLL) header of a network package.
5#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct LinuxSllHeaderSlice<'a> {
7    slice: &'a [u8],
8}
9
10impl<'a> LinuxSllHeaderSlice<'a> {
11    /// Creates a SLL header slice from an other slice.
12    pub fn from_slice(
13        slice: &'a [u8],
14    ) -> Result<LinuxSllHeaderSlice<'a>, err::linux_sll::HeaderSliceError> {
15        //check length
16        if slice.len() < LinuxSllHeader::LEN {
17            return Err(err::linux_sll::HeaderSliceError::Len(err::LenError {
18                required_len: LinuxSllHeader::LEN,
19                len: slice.len(),
20                len_source: LenSource::Slice,
21                layer: err::Layer::LinuxSllHeader,
22                layer_start_offset: 0,
23            }));
24        }
25
26        // check valid packet type
27
28        // SAFETY:
29        // Safe as it is checked at the start of the function that the
30        // length of the slice is at least LinuxSllHeader::LEN (16).
31        let packet_type_val = unsafe { get_unchecked_be_u16(slice.as_ptr()) };
32        if let Err(err) = LinuxSllPacketType::try_from(packet_type_val) {
33            return Err(err::linux_sll::HeaderSliceError::Content(err));
34        }
35
36        // check supported ArpHardwareId
37
38        // SAFETY:
39        // Safe as it is checked at the start of the function that the
40        // length of the slice is at least LinuxSllHeader::LEN (16).
41        let arp_hardware_id = unsafe { get_unchecked_be_u16(slice.as_ptr().add(2)) };
42        let arp_hardware_id = ArpHardwareId::from(arp_hardware_id);
43
44        // SAFETY:
45        // Safe as it is checked at the start of the function that the
46        // length of the slice is at least LinuxSllHeader::LEN (16).
47        let protocol_type = unsafe { get_unchecked_be_u16(slice.as_ptr().add(14)) };
48
49        if let Err(err) = LinuxSllProtocolType::try_from((arp_hardware_id, protocol_type)) {
50            return Err(err::linux_sll::HeaderSliceError::Content(err));
51        }
52
53        //all done
54        Ok(LinuxSllHeaderSlice {
55            // SAFETY:
56            // Safe as slice length is checked to be at least
57            // LinuxSllHeader::LEN (16) before this.
58            slice: unsafe { from_raw_parts(slice.as_ptr(), LinuxSllHeader::LEN) },
59        })
60    }
61
62    /// Converts the given slice into a SLL header slice WITHOUT any checks to
63    /// ensure that the data present is an sll header or that the slice length
64    /// is matching the header length.
65    ///
66    /// If you are not sure what this means, use [`LinuxSllHeaderSlice::from_slice`]
67    /// instead.
68    ///
69    /// # Safety
70    ///
71    /// The caller must ensured that the given slice has the length of
72    /// [`LinuxSllHeader::LEN`] and the fields are valid
73    #[inline]
74    #[cfg(feature = "std")]
75    pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> LinuxSllHeaderSlice {
76        debug_assert!(slice.len() == LinuxSllHeader::LEN);
77        LinuxSllHeaderSlice { slice }
78    }
79
80    /// Returns the slice containing the SLL header
81    #[inline]
82    pub fn slice(&self) -> &'a [u8] {
83        self.slice
84    }
85
86    /// Read the packet type field.
87    #[inline]
88    pub fn packet_type(&self) -> LinuxSllPacketType {
89        // SAFETY:
90        // Safe as the constructor checks that the slice has
91        // at least the length of LinuxSllHeader::LEN (16).
92        let packet_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr()) };
93
94        // SAFETY:
95        // Safe as the constructor checks that the packet type is valid
96        unsafe { LinuxSllPacketType::try_from(packet_type_raw).unwrap_unchecked() }
97    }
98
99    /// Read the arp hardware type field
100    #[inline]
101    pub fn arp_hardware_type(&self) -> ArpHardwareId {
102        // SAFETY:
103        // Safe as the constructor checks that the slice has
104        // at least the length of LinuxSllHeader::LEN (16).
105        let arp_hardware_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) };
106
107        ArpHardwareId::from(arp_hardware_type_raw)
108    }
109
110    /// Read the link layer address length field.
111    #[inline]
112    pub fn sender_address_valid_length(&self) -> u16 {
113        // SAFETY:
114        // Safe as the constructor checks that the slice has
115        // at least the length of LinuxSllHeader::LEN (16).
116        unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(4)) }
117    }
118
119    /// Read the link layer address field. Only the first
120    /// `LinuxSllHeaderSlice::link_layer_address_length` bytes are meaningful
121    #[inline]
122    pub fn sender_address_full(&self) -> [u8; 8] {
123        // SAFETY:
124        // Safe as the constructor checks that the slice has
125        // at least the length of LinuxSllHeader::LEN (16).
126        unsafe { get_unchecked_8_byte_array(self.slice.as_ptr().add(6)) }
127    }
128
129    /// Get the meaningful bytes of the slice of the link layer address
130    #[inline]
131    pub fn sender_address(&self) -> &'a [u8] {
132        let length = self.sender_address_valid_length() as usize;
133        &self.slice[6..min(6 + length, 6 + 8)]
134    }
135
136    /// Read the protocol type field
137    #[inline]
138    pub fn protocol_type(&self) -> LinuxSllProtocolType {
139        let arp_hardware_type = self.arp_hardware_type();
140        // SAFETY:
141        // Safe as the constructor checks that the slice has
142        // at least the length of LinuxSllHeader::LEN (16).
143        let protocol_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(14)) };
144
145        // SAFETY:
146        // Safe as the constructor checks that the arphw + protocol are supported
147        unsafe {
148            LinuxSllProtocolType::try_from((arp_hardware_type, protocol_type_raw))
149                .unwrap_unchecked()
150        }
151    }
152
153    /// Decode all the fields and copy the results to a [`LinuxSllHeader`] struct
154    pub fn to_header(&self) -> LinuxSllHeader {
155        LinuxSllHeader {
156            packet_type: self.packet_type(),
157            arp_hrd_type: self.arp_hardware_type(),
158            sender_address_valid_length: self.sender_address_valid_length(),
159            sender_address: self.sender_address_full(),
160            protocol_type: self.protocol_type(),
161        }
162    }
163}
164
165#[cfg(test)]
166mod test {
167    use super::*;
168    use crate::test_gens::*;
169    use alloc::{format, vec::Vec};
170    use proptest::prelude::*;
171
172    proptest! {
173        #[test]
174        fn from_slice(
175            input in linux_sll_any(),
176            dummy_data in proptest::collection::vec(any::<u8>(), 0..20),
177            bad_packet_type in LinuxSllPacketType::MAX_VAL + 1..=u16::MAX,
178            bad_hw_type in any::<u16>().prop_filter(
179                "hw id must be unknown",
180                |v| ![
181                    ArpHardwareId::NETLINK,
182                    ArpHardwareId::IPGRE,
183                    ArpHardwareId::IEEE80211_RADIOTAP,
184                    ArpHardwareId::FRAD,
185                    ArpHardwareId::ETHERNET,
186                ].iter().any(|&x| *v == x.0)
187            )
188        ) {
189            // serialize
190            let buffer = {
191                let mut buffer: Vec<u8> = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len());
192                input.write(&mut buffer).unwrap();
193                buffer.extend(&dummy_data[..]);
194                buffer
195            };
196
197            // calls with a valid result
198            {
199                let result = LinuxSllHeaderSlice::from_slice(&buffer[..]).unwrap();
200                assert_eq!(&buffer[..LinuxSllHeader::LEN], result.slice());
201            }
202
203            // call with not enough data in the slice
204            for len in 0..=13 {
205                assert_eq!(
206                    LinuxSllHeaderSlice::from_slice(&buffer[..len]),
207                    Err(err::linux_sll::HeaderSliceError::Len(err::LenError{
208                        required_len: LinuxSllHeader::LEN,
209                        len: len,
210                        len_source: LenSource::Slice,
211                        layer: err::Layer::LinuxSllHeader,
212                        layer_start_offset: 0,
213                    }))
214                );
215            }
216
217            // packet_type_val error
218            {
219                let mut modbuf = buffer.clone();
220                let p_be = bad_packet_type.to_be_bytes();
221                modbuf[0] = p_be[0];
222                modbuf[1] = p_be[1];
223                assert_eq!(
224                    LinuxSllHeaderSlice::from_slice(&modbuf),
225                    Err(err::linux_sll::HeaderSliceError::Content(
226                        err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: bad_packet_type }
227                    ))
228                );
229            }
230
231            // hardware_id error
232            {
233                let mut modbuf = buffer.clone();
234                let p_be = bad_hw_type.to_be_bytes();
235                modbuf[2] = p_be[0];
236                modbuf[3] = p_be[1];
237                assert_eq!(
238                    LinuxSllHeaderSlice::from_slice(&modbuf),
239                    Err(err::linux_sll::HeaderSliceError::Content(
240                        err::linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId(bad_hw_type) }
241                    ))
242                );
243            }
244        }
245    }
246
247    proptest! {
248        #[test]
249        fn getters(input in linux_sll_any()) {
250            let buffer = input.to_bytes();
251            let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
252            assert_eq!(input.packet_type, slice.packet_type());
253            assert_eq!(input.arp_hrd_type, slice.arp_hardware_type());
254            assert_eq!(input.sender_address_valid_length, slice.sender_address_valid_length());
255            assert_eq!(input.sender_address, slice.sender_address_full());
256            assert_eq!(&input.sender_address[..usize::from(input.sender_address_valid_length)], slice.sender_address());
257            assert_eq!(input.protocol_type, slice.protocol_type());
258        }
259    }
260
261    proptest! {
262        #[test]
263        fn to_header(input in linux_sll_any()) {
264            let buffer = input.to_bytes();
265            let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
266            assert_eq!(input, slice.to_header());
267        }
268    }
269
270    proptest! {
271        #[test]
272        fn clone_eq(input in linux_sll_any()) {
273            let buffer = input.to_bytes();
274            let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
275            assert_eq!(slice, slice.clone());
276        }
277    }
278
279    proptest! {
280        #[test]
281        fn dbg(input in linux_sll_any()) {
282            let buffer = input.to_bytes();
283            let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
284            assert_eq!(
285                &format!(
286                    "LinuxSllHeaderSlice {{ slice: {:?} }}",
287                    slice.slice()
288                ),
289                &format!("{:?}", slice)
290            );
291        }
292    }
293}