1 use byteorder::{ByteOrder, NetworkEndian}; 2 use core::fmt; 3 4 use super::{Error, Result}; 5 6 pub use super::EthernetProtocol as Protocol; 7 8 enum_with_unknown! { 9 /// ARP hardware type. 10 pub enum Hardware(u16) { 11 Ethernet = 1 12 } 13 } 14 15 enum_with_unknown! { 16 /// ARP operation type. 17 pub enum Operation(u16) { 18 Request = 1, 19 Reply = 2 20 } 21 } 22 23 /// A read/write wrapper around an Address Resolution Protocol packet buffer. 24 #[derive(Debug, PartialEq, Eq, Clone)] 25 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 26 pub struct Packet<T: AsRef<[u8]>> { 27 buffer: T, 28 } 29 30 mod field { 31 #![allow(non_snake_case)] 32 33 use crate::wire::field::*; 34 35 pub const HTYPE: Field = 0..2; 36 pub const PTYPE: Field = 2..4; 37 pub const HLEN: usize = 4; 38 pub const PLEN: usize = 5; 39 pub const OPER: Field = 6..8; 40 41 #[inline] SHA(hardware_len: u8, _protocol_len: u8) -> Field42 pub const fn SHA(hardware_len: u8, _protocol_len: u8) -> Field { 43 let start = OPER.end; 44 start..(start + hardware_len as usize) 45 } 46 47 #[inline] SPA(hardware_len: u8, protocol_len: u8) -> Field48 pub const fn SPA(hardware_len: u8, protocol_len: u8) -> Field { 49 let start = SHA(hardware_len, protocol_len).end; 50 start..(start + protocol_len as usize) 51 } 52 53 #[inline] THA(hardware_len: u8, protocol_len: u8) -> Field54 pub const fn THA(hardware_len: u8, protocol_len: u8) -> Field { 55 let start = SPA(hardware_len, protocol_len).end; 56 start..(start + hardware_len as usize) 57 } 58 59 #[inline] TPA(hardware_len: u8, protocol_len: u8) -> Field60 pub const fn TPA(hardware_len: u8, protocol_len: u8) -> Field { 61 let start = THA(hardware_len, protocol_len).end; 62 start..(start + protocol_len as usize) 63 } 64 } 65 66 impl<T: AsRef<[u8]>> Packet<T> { 67 /// Imbue a raw octet buffer with ARP packet structure. new_unchecked(buffer: T) -> Packet<T>68 pub const fn new_unchecked(buffer: T) -> Packet<T> { 69 Packet { buffer } 70 } 71 72 /// Shorthand for a combination of [new_unchecked] and [check_len]. 73 /// 74 /// [new_unchecked]: #method.new_unchecked 75 /// [check_len]: #method.check_len new_checked(buffer: T) -> Result<Packet<T>>76 pub fn new_checked(buffer: T) -> Result<Packet<T>> { 77 let packet = Self::new_unchecked(buffer); 78 packet.check_len()?; 79 Ok(packet) 80 } 81 82 /// Ensure that no accessor method will panic if called. 83 /// Returns `Err(Error)` if the buffer is too short. 84 /// 85 /// The result of this check is invalidated by calling [set_hardware_len] or 86 /// [set_protocol_len]. 87 /// 88 /// [set_hardware_len]: #method.set_hardware_len 89 /// [set_protocol_len]: #method.set_protocol_len 90 #[allow(clippy::if_same_then_else)] check_len(&self) -> Result<()>91 pub fn check_len(&self) -> Result<()> { 92 let len = self.buffer.as_ref().len(); 93 if len < field::OPER.end { 94 Err(Error) 95 } else if len < field::TPA(self.hardware_len(), self.protocol_len()).end { 96 Err(Error) 97 } else { 98 Ok(()) 99 } 100 } 101 102 /// Consume the packet, returning the underlying buffer. into_inner(self) -> T103 pub fn into_inner(self) -> T { 104 self.buffer 105 } 106 107 /// Return the hardware type field. 108 #[inline] hardware_type(&self) -> Hardware109 pub fn hardware_type(&self) -> Hardware { 110 let data = self.buffer.as_ref(); 111 let raw = NetworkEndian::read_u16(&data[field::HTYPE]); 112 Hardware::from(raw) 113 } 114 115 /// Return the protocol type field. 116 #[inline] protocol_type(&self) -> Protocol117 pub fn protocol_type(&self) -> Protocol { 118 let data = self.buffer.as_ref(); 119 let raw = NetworkEndian::read_u16(&data[field::PTYPE]); 120 Protocol::from(raw) 121 } 122 123 /// Return the hardware length field. 124 #[inline] hardware_len(&self) -> u8125 pub fn hardware_len(&self) -> u8 { 126 let data = self.buffer.as_ref(); 127 data[field::HLEN] 128 } 129 130 /// Return the protocol length field. 131 #[inline] protocol_len(&self) -> u8132 pub fn protocol_len(&self) -> u8 { 133 let data = self.buffer.as_ref(); 134 data[field::PLEN] 135 } 136 137 /// Return the operation field. 138 #[inline] operation(&self) -> Operation139 pub fn operation(&self) -> Operation { 140 let data = self.buffer.as_ref(); 141 let raw = NetworkEndian::read_u16(&data[field::OPER]); 142 Operation::from(raw) 143 } 144 145 /// Return the source hardware address field. source_hardware_addr(&self) -> &[u8]146 pub fn source_hardware_addr(&self) -> &[u8] { 147 let data = self.buffer.as_ref(); 148 &data[field::SHA(self.hardware_len(), self.protocol_len())] 149 } 150 151 /// Return the source protocol address field. source_protocol_addr(&self) -> &[u8]152 pub fn source_protocol_addr(&self) -> &[u8] { 153 let data = self.buffer.as_ref(); 154 &data[field::SPA(self.hardware_len(), self.protocol_len())] 155 } 156 157 /// Return the target hardware address field. target_hardware_addr(&self) -> &[u8]158 pub fn target_hardware_addr(&self) -> &[u8] { 159 let data = self.buffer.as_ref(); 160 &data[field::THA(self.hardware_len(), self.protocol_len())] 161 } 162 163 /// Return the target protocol address field. target_protocol_addr(&self) -> &[u8]164 pub fn target_protocol_addr(&self) -> &[u8] { 165 let data = self.buffer.as_ref(); 166 &data[field::TPA(self.hardware_len(), self.protocol_len())] 167 } 168 } 169 170 impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> { 171 /// Set the hardware type field. 172 #[inline] set_hardware_type(&mut self, value: Hardware)173 pub fn set_hardware_type(&mut self, value: Hardware) { 174 let data = self.buffer.as_mut(); 175 NetworkEndian::write_u16(&mut data[field::HTYPE], value.into()) 176 } 177 178 /// Set the protocol type field. 179 #[inline] set_protocol_type(&mut self, value: Protocol)180 pub fn set_protocol_type(&mut self, value: Protocol) { 181 let data = self.buffer.as_mut(); 182 NetworkEndian::write_u16(&mut data[field::PTYPE], value.into()) 183 } 184 185 /// Set the hardware length field. 186 #[inline] set_hardware_len(&mut self, value: u8)187 pub fn set_hardware_len(&mut self, value: u8) { 188 let data = self.buffer.as_mut(); 189 data[field::HLEN] = value 190 } 191 192 /// Set the protocol length field. 193 #[inline] set_protocol_len(&mut self, value: u8)194 pub fn set_protocol_len(&mut self, value: u8) { 195 let data = self.buffer.as_mut(); 196 data[field::PLEN] = value 197 } 198 199 /// Set the operation field. 200 #[inline] set_operation(&mut self, value: Operation)201 pub fn set_operation(&mut self, value: Operation) { 202 let data = self.buffer.as_mut(); 203 NetworkEndian::write_u16(&mut data[field::OPER], value.into()) 204 } 205 206 /// Set the source hardware address field. 207 /// 208 /// # Panics 209 /// The function panics if `value` is not `self.hardware_len()` long. set_source_hardware_addr(&mut self, value: &[u8])210 pub fn set_source_hardware_addr(&mut self, value: &[u8]) { 211 let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len()); 212 let data = self.buffer.as_mut(); 213 data[field::SHA(hardware_len, protocol_len)].copy_from_slice(value) 214 } 215 216 /// Set the source protocol address field. 217 /// 218 /// # Panics 219 /// The function panics if `value` is not `self.protocol_len()` long. set_source_protocol_addr(&mut self, value: &[u8])220 pub fn set_source_protocol_addr(&mut self, value: &[u8]) { 221 let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len()); 222 let data = self.buffer.as_mut(); 223 data[field::SPA(hardware_len, protocol_len)].copy_from_slice(value) 224 } 225 226 /// Set the target hardware address field. 227 /// 228 /// # Panics 229 /// The function panics if `value` is not `self.hardware_len()` long. set_target_hardware_addr(&mut self, value: &[u8])230 pub fn set_target_hardware_addr(&mut self, value: &[u8]) { 231 let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len()); 232 let data = self.buffer.as_mut(); 233 data[field::THA(hardware_len, protocol_len)].copy_from_slice(value) 234 } 235 236 /// Set the target protocol address field. 237 /// 238 /// # Panics 239 /// The function panics if `value` is not `self.protocol_len()` long. set_target_protocol_addr(&mut self, value: &[u8])240 pub fn set_target_protocol_addr(&mut self, value: &[u8]) { 241 let (hardware_len, protocol_len) = (self.hardware_len(), self.protocol_len()); 242 let data = self.buffer.as_mut(); 243 data[field::TPA(hardware_len, protocol_len)].copy_from_slice(value) 244 } 245 } 246 247 impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> { as_ref(&self) -> &[u8]248 fn as_ref(&self) -> &[u8] { 249 self.buffer.as_ref() 250 } 251 } 252 253 use crate::wire::{EthernetAddress, Ipv4Address}; 254 255 /// A high-level representation of an Address Resolution Protocol packet. 256 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 257 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 258 #[non_exhaustive] 259 pub enum Repr { 260 /// An Ethernet and IPv4 Address Resolution Protocol packet. 261 EthernetIpv4 { 262 operation: Operation, 263 source_hardware_addr: EthernetAddress, 264 source_protocol_addr: Ipv4Address, 265 target_hardware_addr: EthernetAddress, 266 target_protocol_addr: Ipv4Address, 267 }, 268 } 269 270 impl Repr { 271 /// Parse an Address Resolution Protocol packet and return a high-level representation, 272 /// or return `Err(Error)` if the packet is not recognized. parse<T: AsRef<[u8]>>(packet: &Packet<T>) -> Result<Repr>273 pub fn parse<T: AsRef<[u8]>>(packet: &Packet<T>) -> Result<Repr> { 274 match ( 275 packet.hardware_type(), 276 packet.protocol_type(), 277 packet.hardware_len(), 278 packet.protocol_len(), 279 ) { 280 (Hardware::Ethernet, Protocol::Ipv4, 6, 4) => Ok(Repr::EthernetIpv4 { 281 operation: packet.operation(), 282 source_hardware_addr: EthernetAddress::from_bytes(packet.source_hardware_addr()), 283 source_protocol_addr: Ipv4Address::from_bytes(packet.source_protocol_addr()), 284 target_hardware_addr: EthernetAddress::from_bytes(packet.target_hardware_addr()), 285 target_protocol_addr: Ipv4Address::from_bytes(packet.target_protocol_addr()), 286 }), 287 _ => Err(Error), 288 } 289 } 290 291 /// Return the length of a packet that will be emitted from this high-level representation. buffer_len(&self) -> usize292 pub const fn buffer_len(&self) -> usize { 293 match *self { 294 Repr::EthernetIpv4 { .. } => field::TPA(6, 4).end, 295 } 296 } 297 298 /// Emit a high-level representation into an Address Resolution Protocol packet. emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>)299 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) { 300 match *self { 301 Repr::EthernetIpv4 { 302 operation, 303 source_hardware_addr, 304 source_protocol_addr, 305 target_hardware_addr, 306 target_protocol_addr, 307 } => { 308 packet.set_hardware_type(Hardware::Ethernet); 309 packet.set_protocol_type(Protocol::Ipv4); 310 packet.set_hardware_len(6); 311 packet.set_protocol_len(4); 312 packet.set_operation(operation); 313 packet.set_source_hardware_addr(source_hardware_addr.as_bytes()); 314 packet.set_source_protocol_addr(source_protocol_addr.as_bytes()); 315 packet.set_target_hardware_addr(target_hardware_addr.as_bytes()); 316 packet.set_target_protocol_addr(target_protocol_addr.as_bytes()); 317 } 318 } 319 } 320 } 321 322 impl<T: AsRef<[u8]>> fmt::Display for Packet<T> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result323 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 324 match Repr::parse(self) { 325 Ok(repr) => write!(f, "{repr}"), 326 _ => { 327 write!(f, "ARP (unrecognized)")?; 328 write!( 329 f, 330 " htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}", 331 self.hardware_type(), 332 self.protocol_type(), 333 self.hardware_len(), 334 self.protocol_len(), 335 self.operation() 336 )?; 337 write!( 338 f, 339 " sha={:?} spa={:?} tha={:?} tpa={:?}", 340 self.source_hardware_addr(), 341 self.source_protocol_addr(), 342 self.target_hardware_addr(), 343 self.target_protocol_addr() 344 )?; 345 Ok(()) 346 } 347 } 348 } 349 } 350 351 impl fmt::Display for Repr { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result352 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 353 match *self { 354 Repr::EthernetIpv4 { 355 operation, 356 source_hardware_addr, 357 source_protocol_addr, 358 target_hardware_addr, 359 target_protocol_addr, 360 } => { 361 write!( 362 f, 363 "ARP type=Ethernet+IPv4 src={source_hardware_addr}/{source_protocol_addr} tgt={target_hardware_addr}/{target_protocol_addr} op={operation:?}" 364 ) 365 } 366 } 367 } 368 } 369 370 use crate::wire::pretty_print::{PrettyIndent, PrettyPrint}; 371 372 impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> { pretty_print( buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter, indent: &mut PrettyIndent, ) -> fmt::Result373 fn pretty_print( 374 buffer: &dyn AsRef<[u8]>, 375 f: &mut fmt::Formatter, 376 indent: &mut PrettyIndent, 377 ) -> fmt::Result { 378 match Packet::new_checked(buffer) { 379 Err(err) => write!(f, "{indent}({err})"), 380 Ok(packet) => write!(f, "{indent}{packet}"), 381 } 382 } 383 } 384 385 #[cfg(test)] 386 mod test { 387 use super::*; 388 389 static PACKET_BYTES: [u8; 28] = [ 390 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x21, 391 0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x41, 0x42, 0x43, 0x44, 392 ]; 393 394 #[test] test_deconstruct()395 fn test_deconstruct() { 396 let packet = Packet::new_unchecked(&PACKET_BYTES[..]); 397 assert_eq!(packet.hardware_type(), Hardware::Ethernet); 398 assert_eq!(packet.protocol_type(), Protocol::Ipv4); 399 assert_eq!(packet.hardware_len(), 6); 400 assert_eq!(packet.protocol_len(), 4); 401 assert_eq!(packet.operation(), Operation::Request); 402 assert_eq!( 403 packet.source_hardware_addr(), 404 &[0x11, 0x12, 0x13, 0x14, 0x15, 0x16] 405 ); 406 assert_eq!(packet.source_protocol_addr(), &[0x21, 0x22, 0x23, 0x24]); 407 assert_eq!( 408 packet.target_hardware_addr(), 409 &[0x31, 0x32, 0x33, 0x34, 0x35, 0x36] 410 ); 411 assert_eq!(packet.target_protocol_addr(), &[0x41, 0x42, 0x43, 0x44]); 412 } 413 414 #[test] test_construct()415 fn test_construct() { 416 let mut bytes = vec![0xa5; 28]; 417 let mut packet = Packet::new_unchecked(&mut bytes); 418 packet.set_hardware_type(Hardware::Ethernet); 419 packet.set_protocol_type(Protocol::Ipv4); 420 packet.set_hardware_len(6); 421 packet.set_protocol_len(4); 422 packet.set_operation(Operation::Request); 423 packet.set_source_hardware_addr(&[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]); 424 packet.set_source_protocol_addr(&[0x21, 0x22, 0x23, 0x24]); 425 packet.set_target_hardware_addr(&[0x31, 0x32, 0x33, 0x34, 0x35, 0x36]); 426 packet.set_target_protocol_addr(&[0x41, 0x42, 0x43, 0x44]); 427 assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]); 428 } 429 packet_repr() -> Repr430 fn packet_repr() -> Repr { 431 Repr::EthernetIpv4 { 432 operation: Operation::Request, 433 source_hardware_addr: EthernetAddress::from_bytes(&[ 434 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 435 ]), 436 source_protocol_addr: Ipv4Address::from_bytes(&[0x21, 0x22, 0x23, 0x24]), 437 target_hardware_addr: EthernetAddress::from_bytes(&[ 438 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 439 ]), 440 target_protocol_addr: Ipv4Address::from_bytes(&[0x41, 0x42, 0x43, 0x44]), 441 } 442 } 443 444 #[test] test_parse()445 fn test_parse() { 446 let packet = Packet::new_unchecked(&PACKET_BYTES[..]); 447 let repr = Repr::parse(&packet).unwrap(); 448 assert_eq!(repr, packet_repr()); 449 } 450 451 #[test] test_emit()452 fn test_emit() { 453 let mut bytes = vec![0xa5; 28]; 454 let mut packet = Packet::new_unchecked(&mut bytes); 455 packet_repr().emit(&mut packet); 456 assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]); 457 } 458 } 459