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