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