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