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