• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use 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)]
9 pub struct LinuxSllSlice<'a> {
10     header_slice: LinuxSllHeaderSlice<'a>,
11     header_and_payload_slice: &'a [u8],
12 }
13 
14 impl<'a> LinuxSllSlice<'a> {
15     /// Try creating a [`LinuxSllSlice`] from a slice containing the
16     /// header & payload
from_slice( slice: &'a [u8], ) -> Result<LinuxSllSlice<'a>, err::linux_sll::HeaderSliceError>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]
slice(&self) -> &'a [u8]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]
packet_type(&self) -> LinuxSllPacketType50     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]
arp_hardware_type(&self) -> ArpHardwareId56     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]
sender_address_valid_length(&self) -> u1662     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]
sender_address_full(&self) -> [u8; 8]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]
sender_address(&self) -> &'a [u8]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]
protocol_type(&self) -> LinuxSllProtocolType82     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
to_header(&self) -> LinuxSllHeader88     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
header_slice(&self) -> &[u8]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]
payload(&self) -> LinuxSllPayloadSlice<'a>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]
payload_slice(&self) -> &'a [u8]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]
header_len(&self) -> usize130     pub const fn header_len(&self) -> usize {
131         LinuxSllHeader::LEN
132     }
133 }
134 
135 impl core::fmt::Debug for LinuxSllSlice<'_> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result136     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)]
145 mod 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.protocol_type, slice.protocol_type());
197             assert_eq!(&payload, slice.payload_slice());
198             assert_eq!(
199                 LinuxSllPayloadSlice{
200                     payload: &payload,
201                     protocol_type: linux_sll.protocol_type,
202                 },
203                 slice.payload()
204             );
205             assert_eq!(linux_sll, slice.to_header());
206             assert_eq!(&data, slice.slice());
207             assert_eq!(&data[..LinuxSllHeader::LEN], slice.header_slice());
208         }
209     }
210 
211     proptest! {
212         #[test]
213         fn from_slice(linux_sll in linux_sll_any()) {
214 
215             let payload: [u8;10] = [1,2,3,4,5,6,7,8,9,10];
216             let data = {
217                 let mut data = Vec::with_capacity(
218                     linux_sll.header_len() +
219                     payload.len()
220                 );
221                 data.extend_from_slice(&linux_sll.to_bytes());
222                 data.extend_from_slice(&payload);
223                 data
224             };
225 
226             // normal decode
227             {
228                 let slice = LinuxSllSlice::from_slice(&data).unwrap();
229                 assert_eq!(slice.to_header(), linux_sll);
230                 assert_eq!(slice.payload_slice(), &payload);
231             }
232 
233             // decode without payload
234             {
235                 let slice = LinuxSllSlice::from_slice(&data[..LinuxSllHeader::LEN]).unwrap();
236                 assert_eq!(slice.to_header(), linux_sll);
237                 assert_eq!(slice.payload_slice(), &[]);
238             }
239 
240             // length error
241             for len in 0..LinuxSllHeader::LEN {
242                 assert_eq!(
243                     LinuxSllSlice::from_slice(&data[..len]).unwrap_err(),
244                     err::linux_sll::HeaderSliceError::Len(err::LenError{
245                         required_len: LinuxSllHeader::LEN,
246                         len,
247                         len_source: LenSource::Slice,
248                         layer: Layer::LinuxSllHeader,
249                         layer_start_offset: 0
250                     })
251                 );
252             }
253         }
254     }
255 }
256