• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{err, ArpHardwareId, LinuxSllHeaderSlice, LinuxSllPacketType, LinuxSllProtocolType};
2 
3 /// Linux Cooked Capture v1 (SLL) Header
4 #[derive(Clone, Debug, Eq, PartialEq)]
5 pub 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 adress that is valid
11     pub sender_address_valid_length: u16,
12     /// The link-layer adress 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 
21 impl 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]
from_slice( slice: &[u8], ) -> Result<(LinuxSllHeader, &[u8]), err::linux_sll::HeaderSliceError>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]
from_bytes(bytes: [u8; 16]) -> Result<LinuxSllHeader, err::linux_sll::HeaderError>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")))]
read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, ) -> Result<LinuxSllHeader, err::ReadError>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.
write_to_slice<'a>( &self, slice: &'a mut [u8], ) -> Result<&'a mut [u8], err::SliceWriteSpaceError>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]
write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error>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]
header_len(&self) -> usize106     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]
to_bytes(&self) -> [u8; Self::LEN]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)]
142 mod 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 }
334