network_types/
arp.rs

1use core::mem::{self};
2
3use crate::{getter_be, setter_be};
4
5/// Represents an Address Resolution Protocol (ARP) header.
6///
7/// The ARP header is typically found after the Ethernet header and is used to
8/// map a network protocol address (like an IPv4 address) to a hardware
9/// address (like a MAC address).
10#[repr(C)]
11#[derive(Debug, Copy, Clone, Default)]
12#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
13pub struct ArpHdr {
14    /// Hardware type (HTYPE): Specifies the network link protocol type.
15    /// E.g., Ethernet is 1.
16    pub htype: [u8; 2],
17    /// Protocol type (PTYPE): Specifies the internetwork protocol for which
18    /// the ARP request is intended. For IPv4, this has the value 0x0800.
19    pub ptype: [u8; 2],
20    /// Hardware address length (HLEN): Length in bytes of a hardware address.
21    /// Ethernet addresses size is 6.
22    pub hlen: u8,
23    /// Protocol address length (PLEN): Length in bytes of a logical address.
24    /// IPv4 addresses size is 4.
25    pub plen: u8,
26    /// Operation (OPER): Specifies the operation that the sender is performing:
27    /// 1 for request, 2 for reply.
28    pub oper: [u8; 2],
29    /// Sender hardware address (SHA): The hardware address of the sender.
30    pub sha: [u8; 6],
31    /// Sender protocol address (SPA): The protocol address of the sender.
32    pub spa: [u8; 4],
33    /// Target hardware address (THA): The hardware address of the intended
34    /// receiver. This field is ignored in an ARP request.
35    pub tha: [u8; 6],
36    /// Target protocol address (TPA): The protocol address of the intended
37    /// receiver.
38    pub tpa: [u8; 4],
39}
40
41impl ArpHdr {
42    /// The size of the ARP header in bytes.
43    pub const LEN: usize = mem::size_of::<ArpHdr>();
44
45    /// Creates a new `ArpHdr` with all fields initialized to zero.
46    /// This is an alias for `ArpHdr::default()`.
47    pub fn new() -> Self {
48        Self::default()
49    }
50
51    /// Returns the hardware type field.
52    #[inline]
53    pub fn htype(&self) -> u16 {
54        // SAFETY: Pointer arithmetic in bounds of the struct.
55        unsafe { getter_be!(self, htype, u16) }
56    }
57
58    /// Sets the hardware type field.
59    ///
60    /// # Arguments
61    ///
62    /// * `htype` - A 2-byte array representing the hardware type.
63    #[inline]
64    pub fn set_htype(&mut self, htype: u16) {
65        // SAFETY: Pointer arithmetic in bounds of the struct.
66        unsafe { setter_be!(self, htype, htype) }
67    }
68
69    /// Returns the protocol type field.
70    #[inline]
71    pub fn ptype(&self) -> u16 {
72        // SAFETY: Pointer arithmetic in bounds of the struct.
73        unsafe { getter_be!(self, ptype, u16) }
74    }
75
76    /// Sets the protocol type field.
77    ///
78    /// # Arguments
79    ///
80    /// * `ptype` - A 2-byte array representing the protocol type.
81    #[inline]
82    pub fn set_ptype(&mut self, ptype: u16) {
83        // SAFETY: Pointer arithmetic in bounds of the struct.
84        unsafe { setter_be!(self, ptype, ptype) }
85    }
86
87    /// Returns the hardware address length field.
88    #[inline]
89    pub fn hlen(&self) -> u8 {
90        self.hlen
91    }
92
93    /// Sets the hardware address length field.
94    ///
95    /// # Arguments
96    ///
97    /// * `hlen` - A u8 value for the hardware address length.
98    #[inline]
99    pub fn set_hlen(&mut self, hlen: u8) {
100        self.hlen = hlen;
101    }
102
103    /// Returns the protocol address length field.
104    #[inline]
105    pub fn plen(&self) -> u8 {
106        self.plen
107    }
108
109    /// Sets the protocol address length field.
110    ///
111    /// # Arguments
112    ///
113    /// * `plen` - A u8 value for the protocol address length.
114    #[inline]
115    pub fn set_plen(&mut self, plen: u8) {
116        self.plen = plen;
117    }
118
119    /// Returns the operation field.
120    #[inline]
121    pub fn oper(&self) -> u16 {
122        // SAFETY: Pointer arithmetic in bounds of the struct.
123        unsafe { getter_be!(self, oper, u16) }
124    }
125
126    /// Sets the operation field.
127    ///
128    /// # Arguments
129    ///
130    /// * `oper` - A 2-byte array representing the operation (e.g., request or reply).
131    #[inline]
132    pub fn set_oper(&mut self, oper: u16) {
133        // SAFETY: Pointer arithmetic in bounds of the struct.
134        unsafe { setter_be!(self, oper, oper) }
135    }
136
137    /// Returns the sender hardware address (SHA) field.
138    #[inline]
139    pub fn sha(&self) -> [u8; 6] {
140        self.sha
141    }
142
143    /// Sets the sender hardware address (SHA) field.
144    ///
145    /// # Arguments
146    ///
147    /// * `hardware_address` - A 6-byte array representing the sender's hardware address.
148    #[inline]
149    pub fn set_sha(&mut self, hardware_address: [u8; 6]) {
150        self.sha = hardware_address
151    }
152
153    /// Returns the sender protocol address (SPA) field.
154    #[inline]
155    pub fn spa(&self) -> [u8; 4] {
156        self.spa
157    }
158
159    /// Sets the sender protocol address (SPA) field.
160    ///
161    /// # Arguments
162    ///
163    /// * `protocol_address` - A 4-byte array representing the sender's protocol address.
164    #[inline]
165    pub fn set_spa(&mut self, protocol_address: [u8; 4]) {
166        self.spa = protocol_address
167    }
168
169    /// Returns the target hardware address (THA) field.
170    #[inline]
171    pub fn tha(&self) -> [u8; 6] {
172        self.tha
173    }
174
175    /// Sets the target hardware address (THA) field.
176    ///
177    /// # Arguments
178    ///
179    /// * `hardware_address` - A 6-byte array representing the target's hardware address.
180    #[inline]
181    pub fn set_tha(&mut self, hardware_address: [u8; 6]) {
182        self.tha = hardware_address
183    }
184
185    /// Returns the target protocol address (TPA) field.
186    #[inline]
187    pub fn tpa(&self) -> [u8; 4] {
188        self.tpa
189    }
190
191    /// Sets the target protocol address (TPA) field.
192    ///
193    /// # Arguments
194    ///
195    /// * `protocol_address` - A 4-byte array representing the target's protocol address.
196    #[inline]
197    pub fn set_tpa(&mut self, protocol_address: [u8; 4]) {
198        self.tpa = protocol_address
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    use super::*;
205
206    #[test]
207    fn test_len_constant() {
208        assert_eq!(ArpHdr::LEN, 28);
209        assert_eq!(ArpHdr::LEN, mem::size_of::<ArpHdr>());
210    }
211
212    #[test]
213    fn test_htype() {
214        let mut hdr = ArpHdr::default();
215        let hw_type = 1u16;
216        hdr.set_htype(hw_type);
217        assert_eq!(hdr.htype(), hw_type);
218    }
219
220    #[test]
221    fn test_ptype() {
222        let mut hdr = ArpHdr::default();
223        let proto_type = 0x0800u16;
224        hdr.set_ptype(proto_type);
225        assert_eq!(hdr.ptype(), proto_type);
226    }
227
228    #[test]
229    fn test_hlen() {
230        let mut hdr = ArpHdr::default();
231        hdr.set_hlen(6);
232        assert_eq!(hdr.hlen(), 6);
233    }
234
235    #[test]
236    fn test_plen() {
237        let mut hdr = ArpHdr::default();
238        hdr.set_plen(4);
239        assert_eq!(hdr.plen(), 4);
240    }
241
242    #[test]
243    fn test_oper() {
244        let mut hdr = ArpHdr::default();
245        let op_request = 1u16;
246        hdr.set_oper(op_request);
247        assert_eq!(hdr.oper(), op_request);
248        let op_reply = 2u16;
249        hdr.set_oper(op_reply);
250        assert_eq!(hdr.oper(), op_reply);
251    }
252
253    #[test]
254    fn test_sha() {
255        let mut hdr = ArpHdr::default();
256        let addr = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55];
257        hdr.set_sha(addr);
258        assert_eq!(hdr.sha(), addr);
259    }
260
261    #[test]
262    fn test_spa() {
263        let mut hdr = ArpHdr::default();
264        let addr = [192, 168, 1, 1];
265        hdr.set_spa(addr);
266        assert_eq!(hdr.spa(), addr);
267    }
268
269    #[test]
270    fn test_tha() {
271        let mut hdr = ArpHdr::default();
272        let addr = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF];
273        hdr.set_tha(addr);
274        assert_eq!(hdr.tha(), addr);
275    }
276
277    #[test]
278    fn test_tpa() {
279        let mut hdr = ArpHdr::default();
280        let addr = [192, 168, 1, 100];
281        hdr.set_tpa(addr);
282        assert_eq!(hdr.tpa(), addr);
283    }
284}