• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use 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)]
6 pub struct LinuxSllHeaderSlice<'a> {
7     slice: &'a [u8],
8 }
9 
10 impl<'a> LinuxSllHeaderSlice<'a> {
11     /// Creates a SLL header slice from an other slice.
from_slice( slice: &'a [u8], ) -> Result<LinuxSllHeaderSlice<'a>, err::linux_sll::HeaderSliceError>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")]
from_slice_unchecked(slice: &[u8]) -> LinuxSllHeaderSlice75     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]
slice(&self) -> &'a [u8]82     pub fn slice(&self) -> &'a [u8] {
83         self.slice
84     }
85 
86     /// Read the packet type field.
87     #[inline]
packet_type(&self) -> LinuxSllPacketType88     pub fn packet_type(&self) -> LinuxSllPacketType {
89         // SAFETY:
90         // Safe as the contructor 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]
arp_hardware_type(&self) -> ArpHardwareId101     pub fn arp_hardware_type(&self) -> ArpHardwareId {
102         // SAFETY:
103         // Safe as the contructor 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]
sender_address_valid_length(&self) -> u16112     pub fn sender_address_valid_length(&self) -> u16 {
113         // SAFETY:
114         // Safe as the contructor 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]
sender_address_full(&self) -> [u8; 8]122     pub fn sender_address_full(&self) -> [u8; 8] {
123         // SAFETY:
124         // Safe as the contructor 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]
sender_address(&self) -> &'a [u8]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]
protocol_type(&self) -> LinuxSllProtocolType138     pub fn protocol_type(&self) -> LinuxSllProtocolType {
139         let arp_harware_type = self.arp_hardware_type();
140         // SAFETY:
141         // Safe as the contructor 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 arphwd + protocol are supported
147         unsafe {
148             LinuxSllProtocolType::try_from((arp_harware_type, protocol_type_raw)).unwrap_unchecked()
149         }
150     }
151 
152     /// Decode all the fields and copy the results to a [`LinuxSllHeader`] struct
to_header(&self) -> LinuxSllHeader153     pub fn to_header(&self) -> LinuxSllHeader {
154         LinuxSllHeader {
155             packet_type: self.packet_type(),
156             arp_hrd_type: self.arp_hardware_type(),
157             sender_address_valid_length: self.sender_address_valid_length(),
158             sender_address: self.sender_address_full(),
159             protocol_type: self.protocol_type(),
160         }
161     }
162 }
163 
164 #[cfg(test)]
165 mod test {
166     use super::*;
167     use crate::test_gens::*;
168     use alloc::{format, vec::Vec};
169     use proptest::prelude::*;
170 
171     proptest! {
172         #[test]
173         fn from_slice(
174             input in linux_sll_any(),
175             dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
176         ) {
177             // serialize
178             let mut buffer: Vec<u8> = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len());
179             input.write(&mut buffer).unwrap();
180             buffer.extend(&dummy_data[..]);
181 
182             // calls with a valid result
183             {
184                 let result = LinuxSllHeaderSlice::from_slice(&buffer[..]).unwrap();
185                 assert_eq!(&buffer[..LinuxSllHeader::LEN], result.slice());
186             }
187 
188             // call with not enough data in the slice
189             for len in 0..=13 {
190                 assert_eq!(
191                     LinuxSllHeaderSlice::from_slice(&buffer[..len]),
192                     Err(err::linux_sll::HeaderSliceError::Len(err::LenError{
193                         required_len: LinuxSllHeader::LEN,
194                         len: len,
195                         len_source: LenSource::Slice,
196                         layer: err::Layer::LinuxSllHeader,
197                         layer_start_offset: 0,
198                     }))
199                 );
200             }
201         }
202     }
203 
204     proptest! {
205         #[test]
206         fn getters(input in linux_sll_any()) {
207             let buffer = input.to_bytes();
208             let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
209             assert_eq!(input.packet_type, slice.packet_type());
210             assert_eq!(input.arp_hrd_type, slice.arp_hardware_type());
211             assert_eq!(input.sender_address_valid_length, slice.sender_address_valid_length());
212             assert_eq!(input.sender_address, slice.sender_address_full());
213             assert_eq!(input.protocol_type, slice.protocol_type());
214         }
215     }
216 
217     proptest! {
218         #[test]
219         fn to_header(input in linux_sll_any()) {
220             let buffer = input.to_bytes();
221             let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
222             assert_eq!(input, slice.to_header());
223         }
224     }
225 
226     proptest! {
227         #[test]
228         fn clone_eq(input in linux_sll_any()) {
229             let buffer = input.to_bytes();
230             let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
231             assert_eq!(slice, slice.clone());
232         }
233     }
234 
235     proptest! {
236         #[test]
237         fn dbg(input in linux_sll_any()) {
238             let buffer = input.to_bytes();
239             let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
240             assert_eq!(
241                 &format!(
242                     "LinuxSllHeaderSlice {{ slice: {:?} }}",
243                     slice.slice()
244                 ),
245                 &format!("{:?}", slice)
246             );
247         }
248     }
249 }
250