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

etherparse/link/
linux_sll_slice.rs

1use crate::{
2    err::{self, Layer},
3    ArpHardwareId, LenSource, LinuxSllHeader, LinuxSllHeaderSlice, LinuxSllPacketType,
4    LinuxSllPayloadSlice, LinuxSllProtocolType,
5};
6
7/// Slice containing a Linux Cooked Capture v1 (SLL) header & payload.
8#[derive(Clone, Eq, PartialEq)]
9pub struct LinuxSllSlice<'a> {
10    header_slice: LinuxSllHeaderSlice<'a>,
11    header_and_payload_slice: &'a [u8],
12}
13
14impl<'a> LinuxSllSlice<'a> {
15    /// Try creating a [`LinuxSllSlice`] from a slice containing the
16    /// header & payload
17    pub fn from_slice(
18        slice: &'a [u8],
19    ) -> Result<LinuxSllSlice<'a>, err::linux_sll::HeaderSliceError> {
20        // check length
21        if slice.len() < LinuxSllHeader::LEN {
22            return Err(err::linux_sll::HeaderSliceError::Len(err::LenError {
23                required_len: LinuxSllHeader::LEN,
24                len: slice.len(),
25                len_source: LenSource::Slice,
26                layer: Layer::LinuxSllHeader,
27                layer_start_offset: 0,
28            }));
29        }
30
31        // extract header
32        match LinuxSllHeaderSlice::from_slice(&slice[0..LinuxSllHeader::LEN]) {
33            Err(err) => Err(err),
34            Ok(header_slice) => Ok(LinuxSllSlice {
35                header_slice,
36                header_and_payload_slice: slice,
37            }),
38        }
39    }
40
41    /// Returns the slice containing the Linux Cooked Capture v1 (SLL) header &
42    /// payload.
43    #[inline]
44    pub fn slice(&self) -> &'a [u8] {
45        self.header_and_payload_slice
46    }
47
48    /// Read the packet type field from the header
49    #[inline]
50    pub fn packet_type(&self) -> LinuxSllPacketType {
51        self.header_slice.packet_type()
52    }
53
54    /// Read the arp hardware type field from the header
55    #[inline]
56    pub fn arp_hardware_type(&self) -> ArpHardwareId {
57        self.header_slice.arp_hardware_type()
58    }
59
60    /// Read the link layer address length field from the header
61    #[inline]
62    pub fn sender_address_valid_length(&self) -> u16 {
63        self.header_slice.sender_address_valid_length()
64    }
65
66    /// Read the link layer address field from the header. Only the first
67    /// `LinuxSllSlice::link_layer_address_length` bytes are meaningful
68    #[inline]
69    pub fn sender_address_full(&self) -> [u8; 8] {
70        self.header_slice.sender_address_full()
71    }
72
73    /// Get the meaningful bytes of the slice of the link layer address from
74    /// the header
75    #[inline]
76    pub fn sender_address(&self) -> &'a [u8] {
77        self.header_slice.sender_address()
78    }
79
80    /// Read the protocol type field from the header
81    #[inline]
82    pub fn protocol_type(&self) -> LinuxSllProtocolType {
83        self.header_slice.protocol_type()
84    }
85
86    /// Decode all the header fields and copy the results to a
87    /// [`LinuxSllHeader`] struct
88    pub fn to_header(&self) -> LinuxSllHeader {
89        LinuxSllHeader {
90            packet_type: self.packet_type(),
91            arp_hrd_type: self.arp_hardware_type(),
92            sender_address_valid_length: self.sender_address_valid_length(),
93            sender_address: self.sender_address_full(),
94            protocol_type: self.protocol_type(),
95        }
96    }
97
98    /// Slice only containing the header
99    pub fn header_slice(&self) -> &[u8] {
100        self.header_slice.slice()
101    }
102
103    /// Returns the slice containing the Ethernet II payload & ether type
104    /// identifying it's content type.
105    #[inline]
106    pub fn payload(&self) -> LinuxSllPayloadSlice<'a> {
107        LinuxSllPayloadSlice {
108            protocol_type: self.protocol_type(),
109            payload: self.payload_slice(),
110        }
111    }
112
113    /// Slice only containing the payload
114    #[inline]
115    pub fn payload_slice(&self) -> &'a [u8] {
116        // SAFETY: Safe as the slice length was verified to be at least
117        // LinuxSllHeader::LEN by "from_slice".
118        unsafe {
119            core::slice::from_raw_parts(
120                self.header_and_payload_slice
121                    .as_ptr()
122                    .add(LinuxSllHeader::LEN),
123                self.header_and_payload_slice.len() - LinuxSllHeader::LEN,
124            )
125        }
126    }
127
128    /// Length of the header in bytes (equal to [`crate::LinuxSllHeader::LEN`])
129    #[inline]
130    pub const fn header_len(&self) -> usize {
131        LinuxSllHeader::LEN
132    }
133}
134
135impl core::fmt::Debug for LinuxSllSlice<'_> {
136    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
137        f.debug_struct("LinuxSllSlice")
138            .field("header", &self.to_header())
139            .field("payload", &self.payload())
140            .finish()
141    }
142}
143
144#[cfg(test)]
145mod test {
146    use super::*;
147    use crate::test_gens::*;
148    use alloc::{format, vec::Vec};
149    use proptest::prelude::*;
150
151    proptest! {
152        #[test]
153        fn debug_clone_eq(
154            linux_sll in linux_sll_any()
155        ) {
156            let payload: [u8;8] = [1,2,3,4,5,6,7,8];
157            let mut data = Vec::with_capacity(
158                linux_sll.header_len() +
159                payload.len()
160            );
161            data.extend_from_slice(&linux_sll.to_bytes());
162            data.extend_from_slice(&payload);
163
164            // decode packet
165            let slice = LinuxSllSlice::from_slice(&data).unwrap();
166
167            // check debug output
168            prop_assert_eq!(
169                format!("{:?}", slice),
170                format!(
171                    "LinuxSllSlice {{ header: {:?}, payload: {:?} }}",
172                    slice.to_header(),
173                    slice.payload(),
174                )
175            );
176            prop_assert_eq!(slice.clone(), slice);
177        }
178    }
179
180    proptest! {
181        #[test]
182        fn getters(linux_sll in linux_sll_any()) {
183            let payload: [u8;8] = [1,2,3,4,5,6,7,8];
184            let mut data = Vec::with_capacity(
185                linux_sll.header_len() +
186                payload.len()
187            );
188            data.extend_from_slice(&linux_sll.to_bytes());
189            data.extend_from_slice(&payload);
190
191            let slice = LinuxSllSlice::from_slice(&data).unwrap();
192            assert_eq!(linux_sll.packet_type, slice.packet_type());
193            assert_eq!(linux_sll.arp_hrd_type, slice.arp_hardware_type());
194            assert_eq!(linux_sll.sender_address_valid_length, slice.sender_address_valid_length());
195            assert_eq!(linux_sll.sender_address, slice.sender_address_full());
196            assert_eq!(&linux_sll.sender_address[..usize::from(linux_sll.sender_address_valid_length)], slice.sender_address());
197            assert_eq!(linux_sll.protocol_type, slice.protocol_type());
198            assert_eq!(&payload, slice.payload_slice());
199            assert_eq!(
200                LinuxSllPayloadSlice{
201                    payload: &payload,
202                    protocol_type: linux_sll.protocol_type,
203                },
204                slice.payload()
205            );
206            assert_eq!(linux_sll, slice.to_header());
207            assert_eq!(&data, slice.slice());
208            assert_eq!(&data[..LinuxSllHeader::LEN], slice.header_slice());
209        }
210    }
211
212    proptest! {
213        #[test]
214        fn from_slice(linux_sll in linux_sll_any()) {
215
216            let payload: [u8;10] = [1,2,3,4,5,6,7,8,9,10];
217            let data = {
218                let mut data = Vec::with_capacity(
219                    linux_sll.header_len() +
220                    payload.len()
221                );
222                data.extend_from_slice(&linux_sll.to_bytes());
223                data.extend_from_slice(&payload);
224                data
225            };
226
227            // normal decode
228            {
229                let slice = LinuxSllSlice::from_slice(&data).unwrap();
230                assert_eq!(slice.to_header(), linux_sll);
231                assert_eq!(slice.payload_slice(), &payload);
232            }
233
234            // decode without payload
235            {
236                let slice = LinuxSllSlice::from_slice(&data[..LinuxSllHeader::LEN]).unwrap();
237                assert_eq!(slice.to_header(), linux_sll);
238                assert_eq!(slice.payload_slice(), &[]);
239            }
240
241            // length error
242            for len in 0..LinuxSllHeader::LEN {
243                assert_eq!(
244                    LinuxSllSlice::from_slice(&data[..len]).unwrap_err(),
245                    err::linux_sll::HeaderSliceError::Len(err::LenError{
246                        required_len: LinuxSllHeader::LEN,
247                        len,
248                        len_source: LenSource::Slice,
249                        layer: Layer::LinuxSllHeader,
250                        layer_start_offset: 0
251                    })
252                );
253            }
254        }
255    }
256}