Skip to main content

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