nex_packet/
arp.rs

1//! ARP packet abstraction.
2
3use crate::{
4    ethernet::{ETHERNET_HEADER_LEN, EtherType},
5    packet::{MutablePacket, Packet},
6};
7
8use bytes::{Bytes, BytesMut};
9use core::fmt;
10use nex_core::mac::MacAddr;
11use std::net::Ipv4Addr;
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16/// ARP Header Length.
17pub const ARP_HEADER_LEN: usize = 28;
18/// ARP Minimum Packet Length.
19pub const ARP_PACKET_LEN: usize = ETHERNET_HEADER_LEN + ARP_HEADER_LEN;
20
21/// Represents the ARP operation types.
22#[repr(u16)]
23#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub enum ArpOperation {
26    /// ARP request
27    Request = 1,
28    /// ARP reply
29    Reply = 2,
30    /// RARP request
31    RarpRequest = 3,
32    /// RARP reply
33    RarpReply = 4,
34    /// InARP request
35    InRequest = 8,
36    /// InARP reply
37    InReply = 9,
38    /// ARP NAK
39    Nak = 10,
40    /// Unknown ARP operation
41    Unknown(u16),
42}
43
44impl ArpOperation {
45    /// Constructs a new ArpOperation from u16
46    pub fn new(value: u16) -> ArpOperation {
47        match value {
48            1 => ArpOperation::Request,
49            2 => ArpOperation::Reply,
50            3 => ArpOperation::RarpRequest,
51            4 => ArpOperation::RarpReply,
52            8 => ArpOperation::InRequest,
53            9 => ArpOperation::InReply,
54            10 => ArpOperation::Nak,
55            _ => ArpOperation::Unknown(value),
56        }
57    }
58    /// Return the name of the ArpOperation
59    pub fn name(&self) -> &str {
60        match self {
61            ArpOperation::Request => "ARP Request",
62            ArpOperation::Reply => "ARP Reply",
63            ArpOperation::RarpRequest => "RARP Request",
64            ArpOperation::RarpReply => "RARP Reply",
65            ArpOperation::InRequest => "InARP Request",
66            ArpOperation::InReply => "InARP Reply",
67            ArpOperation::Nak => "ARP NAK",
68            ArpOperation::Unknown(_) => "Unknown ARP Operation",
69        }
70    }
71    /// Return the value of the ArpOperation
72    pub fn value(&self) -> u16 {
73        match self {
74            ArpOperation::Request => 1,
75            ArpOperation::Reply => 2,
76            ArpOperation::RarpRequest => 3,
77            ArpOperation::RarpReply => 4,
78            ArpOperation::InRequest => 8,
79            ArpOperation::InReply => 9,
80            ArpOperation::Nak => 10,
81            ArpOperation::Unknown(value) => *value,
82        }
83    }
84}
85
86/// Represents the ARP hardware types.
87#[repr(u16)]
88#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
89#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
90pub enum ArpHardwareType {
91    /// Ethernet (10Mb)
92    Ethernet = 1,
93    /// Experimental Ethernet (3Mb)
94    ExperimentalEthernet = 2,
95    /// Amateur Radio AX.25
96    AmateurRadioAX25 = 3,
97    /// Proteon ProNET Token Ring
98    ProteonProNETTokenRing = 4,
99    /// Chaos
100    Chaos = 5,
101    /// IEEE 802 Networks
102    IEEE802Networks = 6,
103    /// ARCNET
104    ARCNET = 7,
105    /// Hyperchannel
106    Hyperchannel = 8,
107    /// Lanstar
108    Lanstar = 9,
109    /// Autonet Short Address
110    AutonetShortAddress = 10,
111    /// LocalTalk
112    LocalTalk = 11,
113    /// LocalNet (IBM PCNet or SYTEK LocalNET)
114    LocalNet = 12,
115    /// Ultra link
116    UltraLink = 13,
117    /// SMDS
118    SMDS = 14,
119    /// Frame Relay
120    FrameRelay = 15,
121    /// Asynchronous Transmission Mode (ATM)
122    AsynchronousTransmissionMode = 16,
123    /// HDLC
124    HDLC = 17,
125    /// Fibre Channel
126    FibreChannel = 18,
127    /// Asynchronous Transmission Mode (ATM)
128    AsynchronousTransmissionMode2 = 19,
129    /// Serial Line
130    SerialLine = 20,
131    /// Asynchronous Transmission Mode (ATM)
132    AsynchronousTransmissionMode3 = 21,
133    /// MIL-STD-188-220
134    MILSTD188220 = 22,
135    /// Metricom
136    Metricom = 23,
137    /// IEEE 1394.1995
138    IEEE13941995 = 24,
139    /// MAPOS
140    MAPOS = 25,
141    /// Twinaxial
142    Twinaxial = 26,
143    /// EUI-64
144    EUI64 = 27,
145    /// HIPARP
146    HIPARP = 28,
147    /// IP and ARP over ISO 7816-3
148    IPandARPoverISO78163 = 29,
149    /// ARPSec
150    ARPSec = 30,
151    /// IPsec tunnel
152    IPsecTunnel = 31,
153    /// InfiniBand (TM)
154    InfiniBand = 32,
155    /// TIA-102 Project 25 Common Air Interface
156    TIA102Project25CommonAirInterface = 16384,
157    /// Wiegand Interface
158    WiegandInterface = 16385,
159    /// Pure IP
160    PureIP = 16386,
161    /// HW_EXP1
162    HWEXP1 = 65280,
163    /// HW_EXP2
164    HWEXP2 = 65281,
165    /// AEthernet
166    AEthernet = 65282,
167    /// Unknown ARP hardware type
168    Unknown(u16),
169}
170
171impl ArpHardwareType {
172    pub fn new(value: u16) -> ArpHardwareType {
173        match value {
174            1 => ArpHardwareType::Ethernet,
175            2 => ArpHardwareType::ExperimentalEthernet,
176            3 => ArpHardwareType::AmateurRadioAX25,
177            4 => ArpHardwareType::ProteonProNETTokenRing,
178            5 => ArpHardwareType::Chaos,
179            6 => ArpHardwareType::IEEE802Networks,
180            7 => ArpHardwareType::ARCNET,
181            8 => ArpHardwareType::Hyperchannel,
182            9 => ArpHardwareType::Lanstar,
183            10 => ArpHardwareType::AutonetShortAddress,
184            11 => ArpHardwareType::LocalTalk,
185            12 => ArpHardwareType::LocalNet,
186            13 => ArpHardwareType::UltraLink,
187            14 => ArpHardwareType::SMDS,
188            15 => ArpHardwareType::FrameRelay,
189            16 => ArpHardwareType::AsynchronousTransmissionMode,
190            17 => ArpHardwareType::HDLC,
191            18 => ArpHardwareType::FibreChannel,
192            19 => ArpHardwareType::AsynchronousTransmissionMode2,
193            20 => ArpHardwareType::SerialLine,
194            21 => ArpHardwareType::AsynchronousTransmissionMode3,
195            22 => ArpHardwareType::MILSTD188220,
196            23 => ArpHardwareType::Metricom,
197            24 => ArpHardwareType::IEEE13941995,
198            25 => ArpHardwareType::MAPOS,
199            26 => ArpHardwareType::Twinaxial,
200            27 => ArpHardwareType::EUI64,
201            28 => ArpHardwareType::HIPARP,
202            29 => ArpHardwareType::IPandARPoverISO78163,
203            30 => ArpHardwareType::ARPSec,
204            31 => ArpHardwareType::IPsecTunnel,
205            32 => ArpHardwareType::InfiniBand,
206            16384 => ArpHardwareType::TIA102Project25CommonAirInterface,
207            16385 => ArpHardwareType::WiegandInterface,
208            16386 => ArpHardwareType::PureIP,
209            65280 => ArpHardwareType::HWEXP1,
210            65281 => ArpHardwareType::HWEXP2,
211            65282 => ArpHardwareType::AEthernet,
212            _ => ArpHardwareType::Unknown(value),
213        }
214    }
215    /// Return the name of the ARP hardware type
216    pub fn name(&self) -> &str {
217        match self {
218            ArpHardwareType::Ethernet => "Ethernet",
219            ArpHardwareType::ExperimentalEthernet => "Experimental Ethernet",
220            ArpHardwareType::AmateurRadioAX25 => "Amateur Radio AX.25",
221            ArpHardwareType::ProteonProNETTokenRing => "Proteon ProNET Token Ring",
222            ArpHardwareType::Chaos => "Chaos",
223            ArpHardwareType::IEEE802Networks => "IEEE 802 Networks",
224            ArpHardwareType::ARCNET => "ARCNET",
225            ArpHardwareType::Hyperchannel => "Hyperchannel",
226            ArpHardwareType::Lanstar => "Lanstar",
227            ArpHardwareType::AutonetShortAddress => "Autonet Short Address",
228            ArpHardwareType::LocalTalk => "LocalTalk",
229            ArpHardwareType::LocalNet => "LocalNet (IBM PCNet or SYTEK LocalNET)",
230            ArpHardwareType::UltraLink => "Ultra link",
231            ArpHardwareType::SMDS => "SMDS",
232            ArpHardwareType::FrameRelay => "Frame Relay",
233            ArpHardwareType::AsynchronousTransmissionMode => "Asynchronous Transmission Mode (ATM)",
234            ArpHardwareType::HDLC => "HDLC",
235            ArpHardwareType::FibreChannel => "Fibre Channel",
236            ArpHardwareType::AsynchronousTransmissionMode2 => {
237                "Asynchronous Transmission Mode (ATM) 2"
238            }
239            ArpHardwareType::SerialLine => "Serial Line",
240            ArpHardwareType::AsynchronousTransmissionMode3 => {
241                "Asynchronous Transmission Mode (ATM) 3"
242            }
243            ArpHardwareType::MILSTD188220 => "MIL-STD-188-220",
244            ArpHardwareType::Metricom => "Metricom",
245            ArpHardwareType::IEEE13941995 => "IEEE 1394.1995",
246            ArpHardwareType::MAPOS => "MAPOS",
247            ArpHardwareType::Twinaxial => "Twinaxial",
248            ArpHardwareType::EUI64 => "EUI-64",
249            ArpHardwareType::HIPARP => "HIPARP",
250            ArpHardwareType::IPandARPoverISO78163 => "IP and ARP over ISO 7816-3",
251            ArpHardwareType::ARPSec => "ARPSec",
252            ArpHardwareType::IPsecTunnel => "IPsec Tunnel",
253            ArpHardwareType::InfiniBand => "InfiniBand (TM)",
254            ArpHardwareType::TIA102Project25CommonAirInterface => {
255                "TIA-102 Project 25 Common Air Interface"
256            }
257            ArpHardwareType::WiegandInterface => "Wiegand Interface",
258            ArpHardwareType::PureIP => "Pure IP",
259            ArpHardwareType::HWEXP1 => "HW_EXP1",
260            ArpHardwareType::HWEXP2 => "HW_EXP2",
261            ArpHardwareType::AEthernet => "AEthernet",
262            ArpHardwareType::Unknown(_) => "Unknown ARP Hardware Type",
263        }
264    }
265    /// Return the value of the ARP hardware type
266    pub fn value(&self) -> u16 {
267        match self {
268            ArpHardwareType::Ethernet => 1,
269            ArpHardwareType::ExperimentalEthernet => 2,
270            ArpHardwareType::AmateurRadioAX25 => 3,
271            ArpHardwareType::ProteonProNETTokenRing => 4,
272            ArpHardwareType::Chaos => 5,
273            ArpHardwareType::IEEE802Networks => 6,
274            ArpHardwareType::ARCNET => 7,
275            ArpHardwareType::Hyperchannel => 8,
276            ArpHardwareType::Lanstar => 9,
277            ArpHardwareType::AutonetShortAddress => 10,
278            ArpHardwareType::LocalTalk => 11,
279            ArpHardwareType::LocalNet => 12,
280            ArpHardwareType::UltraLink => 13,
281            ArpHardwareType::SMDS => 14,
282            ArpHardwareType::FrameRelay => 15,
283            ArpHardwareType::AsynchronousTransmissionMode => 16,
284            ArpHardwareType::HDLC => 17,
285            ArpHardwareType::FibreChannel => 18,
286            ArpHardwareType::AsynchronousTransmissionMode2 => 19,
287            ArpHardwareType::SerialLine => 20,
288            ArpHardwareType::AsynchronousTransmissionMode3 => 21,
289            ArpHardwareType::MILSTD188220 => 22,
290            ArpHardwareType::Metricom => 23,
291            ArpHardwareType::IEEE13941995 => 24,
292            ArpHardwareType::MAPOS => 25,
293            ArpHardwareType::Twinaxial => 26,
294            ArpHardwareType::EUI64 => 27,
295            ArpHardwareType::HIPARP => 28,
296            ArpHardwareType::IPandARPoverISO78163 => 29,
297            ArpHardwareType::ARPSec => 30,
298            ArpHardwareType::IPsecTunnel => 31,
299            ArpHardwareType::InfiniBand => 32,
300            ArpHardwareType::TIA102Project25CommonAirInterface => 16384,
301            ArpHardwareType::WiegandInterface => 16385,
302            ArpHardwareType::PureIP => 16386,
303            ArpHardwareType::HWEXP1 => 65280,
304            ArpHardwareType::HWEXP2 => 65281,
305            ArpHardwareType::AEthernet => 65282,
306            ArpHardwareType::Unknown(value) => *value,
307        }
308    }
309}
310
311/// Represents the ARP header.
312#[derive(Clone, Debug, PartialEq, Eq)]
313#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
314pub struct ArpHeader {
315    pub hardware_type: ArpHardwareType,
316    pub protocol_type: EtherType,
317    pub hw_addr_len: u8,
318    pub proto_addr_len: u8,
319    pub operation: ArpOperation,
320    pub sender_hw_addr: MacAddr,
321    pub sender_proto_addr: Ipv4Addr,
322    pub target_hw_addr: MacAddr,
323    pub target_proto_addr: Ipv4Addr,
324}
325
326/// Represents an ARP Packet.
327#[derive(Clone, Debug, PartialEq, Eq)]
328#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
329pub struct ArpPacket {
330    /// The ARP header.
331    pub header: ArpHeader,
332    /// The payload of the ARP packet.
333    pub payload: Bytes,
334}
335
336impl Packet for ArpPacket {
337    type Header = ArpHeader;
338    fn from_buf(bytes: &[u8]) -> Option<Self> {
339        if bytes.len() < ARP_HEADER_LEN {
340            return None;
341        }
342        let hardware_type = ArpHardwareType::new(u16::from_be_bytes([bytes[0], bytes[1]]));
343        let protocol_type = EtherType::new(u16::from_be_bytes([bytes[2], bytes[3]]));
344        let hw_addr_len = bytes[4];
345        let proto_addr_len = bytes[5];
346        let operation = ArpOperation::new(u16::from_be_bytes([bytes[6], bytes[7]]));
347        let sender_hw_addr = MacAddr::from_octets(bytes[8..14].try_into().unwrap());
348        let sender_proto_addr = Ipv4Addr::new(bytes[14], bytes[15], bytes[16], bytes[17]);
349        let target_hw_addr = MacAddr::from_octets(bytes[18..24].try_into().unwrap());
350        let target_proto_addr = Ipv4Addr::new(bytes[24], bytes[25], bytes[26], bytes[27]);
351        let payload = Bytes::copy_from_slice(&bytes[ARP_HEADER_LEN..]);
352
353        Some(ArpPacket {
354            header: ArpHeader {
355                hardware_type,
356                protocol_type,
357                hw_addr_len,
358                proto_addr_len,
359                operation,
360                sender_hw_addr,
361                sender_proto_addr,
362                target_hw_addr,
363                target_proto_addr,
364            },
365            payload,
366        })
367    }
368    fn from_bytes(bytes: Bytes) -> Option<Self> {
369        Self::from_buf(&bytes)
370    }
371
372    fn to_bytes(&self) -> Bytes {
373        let mut buf = Vec::with_capacity(ARP_HEADER_LEN + self.payload.len());
374        buf.extend_from_slice(&self.header.hardware_type.value().to_be_bytes());
375        buf.extend_from_slice(&self.header.protocol_type.value().to_be_bytes());
376        buf.push(self.header.hw_addr_len);
377        buf.push(self.header.proto_addr_len);
378        buf.extend_from_slice(&self.header.operation.value().to_be_bytes());
379        buf.extend_from_slice(&self.header.sender_hw_addr.octets());
380        buf.extend_from_slice(&self.header.sender_proto_addr.octets());
381        buf.extend_from_slice(&self.header.target_hw_addr.octets());
382        buf.extend_from_slice(&self.header.target_proto_addr.octets());
383        buf.extend_from_slice(&self.payload);
384
385        Bytes::from(buf)
386    }
387
388    fn header(&self) -> Bytes {
389        self.to_bytes()
390    }
391
392    fn payload(&self) -> Bytes {
393        self.payload.clone()
394    }
395
396    fn header_len(&self) -> usize {
397        ARP_HEADER_LEN
398    }
399    fn payload_len(&self) -> usize {
400        self.payload.len()
401    }
402    fn total_len(&self) -> usize {
403        ARP_HEADER_LEN + self.payload.len()
404    }
405    fn to_bytes_mut(&self) -> BytesMut {
406        let mut buf = BytesMut::with_capacity(self.total_len());
407        buf.extend_from_slice(&self.to_bytes());
408        buf
409    }
410    fn header_mut(&self) -> BytesMut {
411        let mut buf = BytesMut::with_capacity(self.header_len());
412        buf.extend_from_slice(&self.header());
413        buf
414    }
415    fn payload_mut(&self) -> BytesMut {
416        let mut buf = BytesMut::with_capacity(self.payload_len());
417        buf.extend_from_slice(&self.payload());
418        buf
419    }
420
421    fn into_parts(self) -> (Self::Header, Bytes) {
422        (self.header, self.payload)
423    }
424}
425
426impl ArpPacket {
427    /// Create a new ARP packet.
428    pub fn new(header: ArpHeader, payload: Bytes) -> Self {
429        ArpPacket { header, payload }
430    }
431}
432
433impl fmt::Display for ArpPacket {
434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435        write!(
436            f,
437            "ArpPacket {{ hardware_type: {}, protocol_type: {}, hw_addr_len: {}, proto_addr_len: {}, operation: {}, sender_hw_addr: {}, sender_proto_addr: {}, target_hw_addr: {}, target_proto_addr: {} }}",
438            self.header.hardware_type.name(),
439            self.header.protocol_type.name(),
440            self.header.hw_addr_len,
441            self.header.proto_addr_len,
442            self.header.operation.name(),
443            self.header.sender_hw_addr,
444            self.header.sender_proto_addr,
445            self.header.target_hw_addr,
446            self.header.target_proto_addr
447        )
448    }
449}
450
451/// Represents a mutable ARP Packet.
452pub struct MutableArpPacket<'a> {
453    buffer: &'a mut [u8],
454}
455
456impl<'a> MutablePacket<'a> for MutableArpPacket<'a> {
457    type Packet = ArpPacket;
458
459    fn new(buffer: &'a mut [u8]) -> Option<Self> {
460        if buffer.len() < ARP_HEADER_LEN {
461            None
462        } else {
463            Some(Self { buffer })
464        }
465    }
466
467    fn packet(&self) -> &[u8] {
468        &*self.buffer
469    }
470
471    fn packet_mut(&mut self) -> &mut [u8] {
472        &mut *self.buffer
473    }
474
475    fn header(&self) -> &[u8] {
476        &self.packet()[..ARP_HEADER_LEN]
477    }
478
479    fn header_mut(&mut self) -> &mut [u8] {
480        let (header, _) = (&mut *self.buffer).split_at_mut(ARP_HEADER_LEN);
481        header
482    }
483
484    fn payload(&self) -> &[u8] {
485        &self.packet()[ARP_HEADER_LEN..]
486    }
487
488    fn payload_mut(&mut self) -> &mut [u8] {
489        let (_, payload) = (&mut *self.buffer).split_at_mut(ARP_HEADER_LEN);
490        payload
491    }
492}
493
494impl<'a> MutableArpPacket<'a> {
495    /// Create a packet without performing length checks.
496    pub fn new_unchecked(buffer: &'a mut [u8]) -> Self {
497        Self { buffer }
498    }
499
500    fn raw(&self) -> &[u8] {
501        &*self.buffer
502    }
503
504    fn raw_mut(&mut self) -> &mut [u8] {
505        &mut *self.buffer
506    }
507
508    pub fn get_hardware_type(&self) -> ArpHardwareType {
509        ArpHardwareType::new(u16::from_be_bytes([self.raw()[0], self.raw()[1]]))
510    }
511
512    pub fn set_hardware_type(&mut self, ty: ArpHardwareType) {
513        self.raw_mut()[0..2].copy_from_slice(&ty.value().to_be_bytes());
514    }
515
516    pub fn get_protocol_type(&self) -> EtherType {
517        EtherType::new(u16::from_be_bytes([self.raw()[2], self.raw()[3]]))
518    }
519
520    pub fn set_protocol_type(&mut self, ty: EtherType) {
521        self.raw_mut()[2..4].copy_from_slice(&ty.value().to_be_bytes());
522    }
523
524    pub fn get_hw_addr_len(&self) -> u8 {
525        self.raw()[4]
526    }
527
528    pub fn set_hw_addr_len(&mut self, len: u8) {
529        self.raw_mut()[4] = len;
530    }
531
532    pub fn get_proto_addr_len(&self) -> u8 {
533        self.raw()[5]
534    }
535
536    pub fn set_proto_addr_len(&mut self, len: u8) {
537        self.raw_mut()[5] = len;
538    }
539
540    pub fn get_operation(&self) -> ArpOperation {
541        ArpOperation::new(u16::from_be_bytes([self.raw()[6], self.raw()[7]]))
542    }
543
544    pub fn set_operation(&mut self, op: ArpOperation) {
545        self.raw_mut()[6..8].copy_from_slice(&op.value().to_be_bytes());
546    }
547
548    pub fn get_sender_hw_addr(&self) -> MacAddr {
549        MacAddr::from_octets(self.raw()[8..14].try_into().unwrap())
550    }
551
552    pub fn set_sender_hw_addr(&mut self, addr: MacAddr) {
553        self.raw_mut()[8..14].copy_from_slice(&addr.octets());
554    }
555
556    pub fn get_sender_proto_addr(&self) -> Ipv4Addr {
557        Ipv4Addr::new(
558            self.raw()[14],
559            self.raw()[15],
560            self.raw()[16],
561            self.raw()[17],
562        )
563    }
564
565    pub fn set_sender_proto_addr(&mut self, addr: Ipv4Addr) {
566        self.raw_mut()[14..18].copy_from_slice(&addr.octets());
567    }
568
569    pub fn get_target_hw_addr(&self) -> MacAddr {
570        MacAddr::from_octets(self.raw()[18..24].try_into().unwrap())
571    }
572
573    pub fn set_target_hw_addr(&mut self, addr: MacAddr) {
574        self.raw_mut()[18..24].copy_from_slice(&addr.octets());
575    }
576
577    pub fn get_target_proto_addr(&self) -> Ipv4Addr {
578        Ipv4Addr::new(
579            self.raw()[24],
580            self.raw()[25],
581            self.raw()[26],
582            self.raw()[27],
583        )
584    }
585
586    pub fn set_target_proto_addr(&mut self, addr: Ipv4Addr) {
587        self.raw_mut()[24..28].copy_from_slice(&addr.octets());
588    }
589}
590
591#[cfg(test)]
592mod tests {
593    use super::*;
594    #[test]
595    fn test_parse_valid_arp_packet() {
596        let raw = [
597            0x00, 0x01, // Hardware Type: Ethernet
598            0x08, 0x00, // Protocol Type: IPv4
599            0x06, // HW Addr Len
600            0x04, // Proto Addr Len
601            0x00, 0x01, // Operation: Request
602            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // Sender MAC
603            192, 168, 1, 1, // Sender IP
604            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Target MAC
605            192, 168, 1, 2, // Target IP
606        ];
607
608        let padded = [&raw[..], &[0xde, 0xad, 0xbe, 0xef]].concat();
609        let packet = ArpPacket::from_bytes(Bytes::copy_from_slice(&padded)).unwrap();
610
611        assert_eq!(packet.header.hardware_type, ArpHardwareType::Ethernet);
612        assert_eq!(packet.header.protocol_type, EtherType::Ipv4);
613        assert_eq!(packet.header.hw_addr_len, 6);
614        assert_eq!(packet.header.proto_addr_len, 4);
615        assert_eq!(packet.header.operation, ArpOperation::Request);
616        assert_eq!(
617            packet.header.sender_hw_addr,
618            MacAddr::from_octets([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
619        );
620        assert_eq!(
621            packet.header.sender_proto_addr,
622            Ipv4Addr::new(192, 168, 1, 1)
623        );
624        assert_eq!(
625            packet.header.target_hw_addr,
626            MacAddr::from_octets([0, 0, 0, 0, 0, 0])
627        );
628        assert_eq!(
629            packet.header.target_proto_addr,
630            Ipv4Addr::new(192, 168, 1, 2)
631        );
632        assert_eq!(
633            packet.payload,
634            Bytes::from_static(&[0xde, 0xad, 0xbe, 0xef])
635        );
636    }
637
638    #[test]
639    fn test_serialize_roundtrip() {
640        let original = ArpPacket {
641            header: ArpHeader {
642                hardware_type: ArpHardwareType::Ethernet,
643                protocol_type: EtherType::Ipv4,
644                hw_addr_len: 6,
645                proto_addr_len: 4,
646                operation: ArpOperation::Reply,
647                sender_hw_addr: MacAddr::from_octets([1, 2, 3, 4, 5, 6]),
648                sender_proto_addr: Ipv4Addr::new(10, 0, 0, 1),
649                target_hw_addr: MacAddr::from_octets([10, 20, 30, 40, 50, 60]),
650                target_proto_addr: Ipv4Addr::new(10, 0, 0, 2),
651            },
652            payload: Bytes::from_static(&[0xbe, 0xef]),
653        };
654
655        let bytes = original.to_bytes();
656        let parsed = ArpPacket::from_bytes(bytes).unwrap();
657        assert_eq!(original, parsed);
658    }
659
660    #[test]
661    fn test_parse_invalid_short_packet() {
662        let short = Bytes::from_static(&[0u8; 10]);
663        assert!(ArpPacket::from_bytes(short).is_none());
664    }
665
666    #[test]
667    fn test_unknown_operation_and_hw_type() {
668        let raw = [
669            0x99, 0x99, // Hardware Type: unknown
670            0x08, 0x00, // Protocol Type: IPv4
671            0x06, 0x04, 0x99, 0x99, // Operation: unknown
672            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 192, 168, 1, 1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673            192, 168, 1, 2, 0x00, 0x01, 0x02, 0x03,
674        ];
675
676        let packet = ArpPacket::from_bytes(Bytes::copy_from_slice(&raw)).unwrap();
677        match packet.header.hardware_type {
678            ArpHardwareType::Unknown(v) => assert_eq!(v, 0x9999),
679            _ => panic!("Expected unknown hardware type"),
680        }
681        match packet.header.operation {
682            ArpOperation::Unknown(v) => assert_eq!(v, 0x9999),
683            _ => panic!("Expected unknown operation"),
684        }
685    }
686
687    #[test]
688    fn test_mutable_arp_packet_updates() {
689        let mut raw = [
690            0x00, 0x01, // Hardware Type: Ethernet
691            0x08, 0x00, // Protocol Type: IPv4
692            0x06, // HW Addr Len
693            0x04, // Proto Addr Len
694            0x00, 0x01, // Operation: Request
695            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // Sender MAC
696            192, 168, 1, 1, // Sender IP
697            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Target MAC
698            192, 168, 1, 2, // Target IP
699            0xde, 0xad, 0xbe, 0xef, // payload
700        ];
701
702        let mut packet = MutableArpPacket::new(&mut raw).expect("mutable arp");
703        assert_eq!(packet.get_operation(), ArpOperation::Request);
704        packet.set_operation(ArpOperation::Reply);
705        packet.set_sender_proto_addr(Ipv4Addr::new(10, 0, 0, 1));
706        packet.payload_mut()[0] = 0xaa;
707
708        let frozen = packet.freeze().expect("freeze");
709        assert_eq!(frozen.header.operation, ArpOperation::Reply);
710        assert_eq!(frozen.header.sender_proto_addr, Ipv4Addr::new(10, 0, 0, 1));
711        assert_eq!(frozen.payload[0], 0xaa);
712    }
713}