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