1#![no_std]
3
4use core::fmt::{Debug, Display, Formatter};
5
6use byteorder::{ByteOrder, NetworkEndian};
7
8pub const HARDWARE_ETHERNET: u16 = 0x0001;
10
11pub const HARDWARE_SIZE_ETHERNET: u8 = 6;
13
14pub const PROTOCOL_IPV4: u16 = 0x0800;
16
17pub const PROTOCOL_SIZE_IPV4: u8 = 4;
19
20pub const OPCODE_REQUEST: u16 = 1;
22
23pub const OPCODE_REPLY: u16 = 2;
25
26pub const ARP_SIZE: usize = 28;
28
29#[derive(Debug)]
30pub enum Error {
31 InvalidSize,
33
34 InvalidHardwareType,
36
37 InvalidHardwareSize,
39
40 InvalidProtocolType,
42
43 InvalidProtocolSize,
45
46 InvalidOpCode,
48}
49
50impl Display for Error {
51 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
52 write!(f, "{:?}", self)
53 }
54}
55
56pub struct ARPSlice<'a> {
58 data: &'a [u8],
59}
60
61impl<'a> ARPSlice<'a> {
62 #[inline]
64 pub fn hardware_type(&self) -> u16 {
65 NetworkEndian::read_u16(&self.data[0..2])
66 }
67
68 #[inline]
70 pub fn protocol_type(&self) -> u16 {
71 NetworkEndian::read_u16(&self.data[2..4])
72 }
73
74 #[inline]
76 pub fn hardware_size(&self) -> u8 {
77 self.data[4]
78 }
79
80 #[inline]
82 pub fn protocol_size(&self) -> u8 {
83 self.data[5]
84 }
85
86 #[inline]
88 pub fn op_code(&self) -> u16 {
89 NetworkEndian::read_u16(&self.data[6..8])
90 }
91
92 #[inline]
94 pub fn sender_hardware_addr(&self) -> &[u8] {
95 &self.data[8..14]
96 }
97
98 #[inline]
100 pub fn sender_protocol_addr(&self) -> &[u8] {
101 &self.data[14..18]
102 }
103
104 #[inline]
106 pub fn target_hardware_addr(&self) -> &[u8] {
107 &self.data[18..24]
108 }
109
110 #[inline]
112 pub fn target_protocol_addr(&self) -> &[u8] {
113 &self.data[24..28]
114 }
115}
116
117impl<'a> AsRef<[u8]> for ARPSlice<'a> {
118 fn as_ref(&self) -> &[u8] {
119 self.data
120 }
121}
122
123pub fn parse(data: &[u8]) -> Result<ARPSlice, Error> {
125 if data.len() < ARP_SIZE {
126 return Err(Error::InvalidSize);
127 }
128 let slice = ARPSlice { data };
129 if slice.hardware_type() != HARDWARE_ETHERNET {
130 return Err(Error::InvalidHardwareType);
131 }
132 if slice.protocol_type() != PROTOCOL_IPV4 {
133 return Err(Error::InvalidProtocolType);
134 }
135 if slice.op_code() != OPCODE_REQUEST && slice.op_code() != OPCODE_REPLY {
136 return Err(Error::InvalidOpCode);
137 }
138 if slice.hardware_size() != HARDWARE_SIZE_ETHERNET {
139 return Err(Error::InvalidHardwareSize);
140 }
141 if slice.protocol_size() != PROTOCOL_SIZE_IPV4 {
142 return Err(Error::InvalidProtocolSize);
143 }
144 Ok(slice)
145}
146
147pub struct ARPSliceBuilder<'a> {
149 buf: &'a mut [u8],
150}
151
152impl<'a> ARPSliceBuilder<'a> {
153 pub fn new(buf: &'a mut [u8]) -> Result<Self, Error> {
155 if buf.len() < ARP_SIZE {
156 return Err(Error::InvalidSize);
157 }
158 NetworkEndian::write_u16(&mut buf[0..2], HARDWARE_ETHERNET);
159 NetworkEndian::write_u16(&mut buf[2..4], PROTOCOL_IPV4);
160 buf[4] = HARDWARE_SIZE_ETHERNET;
161 buf[5] = PROTOCOL_SIZE_IPV4;
162 NetworkEndian::write_u16(&mut buf[6..8], OPCODE_REQUEST);
163 Ok(Self { buf })
164 }
165
166 pub fn op_code(self, op_code: u16) -> Result<Self, Error> {
168 if op_code != OPCODE_REQUEST && op_code != OPCODE_REPLY {
169 return Err(Error::InvalidOpCode);
170 }
171 NetworkEndian::write_u16(&mut self.buf[6..8], op_code);
172 Ok(Self { buf: self.buf })
173 }
174
175 pub fn sender_hardware_addr(self, ether_addr: &[u8]) -> Result<Self, Error> {
177 if ether_addr.len() < HARDWARE_SIZE_ETHERNET as usize {
178 return Err(Error::InvalidHardwareSize);
179 }
180 self.buf[8..14].copy_from_slice(ðer_addr[0..HARDWARE_SIZE_ETHERNET as usize]);
181 Ok(Self { buf: self.buf })
182 }
183
184 pub fn sender_protocol_addr(self, ipv4_addr: &[u8]) -> Result<Self, Error> {
186 if ipv4_addr.len() < PROTOCOL_SIZE_IPV4 as usize {
187 return Err(Error::InvalidProtocolSize);
188 }
189 self.buf[14..18].copy_from_slice(&ipv4_addr[..4]);
190 Ok(Self { buf: self.buf })
191 }
192
193 pub fn target_hardware_addr(self, ether_addr: &[u8]) -> Result<Self, Error> {
195 if ether_addr.len() < HARDWARE_SIZE_ETHERNET as usize {
196 return Err(Error::InvalidHardwareSize);
197 }
198 self.buf[18..24].copy_from_slice(ðer_addr[..6]);
199 Ok(Self { buf: self.buf })
200 }
201
202 pub fn target_protocol_addr(self, ipv4_addr: &[u8]) -> Result<Self, Error> {
204 if ipv4_addr.len() < PROTOCOL_SIZE_IPV4 as usize {
205 return Err(Error::InvalidProtocolSize);
206 }
207 self.buf[24..28].copy_from_slice(&ipv4_addr[..4]);
208 Ok(Self { buf: self.buf })
209 }
210
211 pub fn build(self) -> &'a mut [u8] {
213 self.buf
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use crate::{ARPSliceBuilder, OPCODE_REPLY, OPCODE_REQUEST, parse};
220
221 #[test]
222 fn parse_request() {
223 let data = [0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x38, 0xfc, 0x98, 0x8b, 0x46, 0x10, 0xc0, 0xa8, 0x13, 0x97, 0xf0, 0x18, 0x98, 0x74, 0xe5, 0xd9, 0xc0, 0xa8, 0x12, 0x70];
224 let arp_slice = parse(&data);
225 assert!(arp_slice.is_ok());
226
227 let arp_slice = arp_slice.unwrap();
228 assert_eq!(arp_slice.op_code(), OPCODE_REQUEST);
229
230 assert_eq!(arp_slice.sender_hardware_addr(), &[0x38, 0xfc, 0x98, 0x8b, 0x46, 0x10]);
231 assert_eq!(arp_slice.sender_protocol_addr(), &[0xc0, 0xa8, 0x13, 0x97]);
232 assert_eq!(arp_slice.target_hardware_addr(), &[0xf0, 0x18, 0x98, 0x74, 0xe5, 0xd9]);
233 assert_eq!(arp_slice.target_protocol_addr(), &[0xc0, 0xa8, 0x12, 0x70]);
234 }
235
236 #[test]
237 fn parse_reply() {
238 let data = [0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0xf0, 0x18, 0x98, 0x74, 0xe5, 0xd9, 0xc0, 0xa8, 0x12, 0x70, 0x38, 0xfc, 0x98, 0x8b, 0x46, 0x10, 0xc0, 0xa8, 0x13, 0x97];
239 let arp_slice = parse(&data);
240 assert!(arp_slice.is_ok());
241
242 let arp_slice = arp_slice.unwrap();
243 assert_eq!(arp_slice.op_code(), OPCODE_REPLY);
244
245 assert_eq!(arp_slice.sender_hardware_addr(), &[0xf0, 0x18, 0x98, 0x74, 0xe5, 0xd9]);
246 assert_eq!(arp_slice.sender_protocol_addr(), &[0xc0, 0xa8, 0x12, 0x70]);
247 assert_eq!(arp_slice.target_hardware_addr(), &[0x38, 0xfc, 0x98, 0x8b, 0x46, 0x10]);
248 assert_eq!(arp_slice.target_protocol_addr(), &[0xc0, 0xa8, 0x13, 0x97]);
249 }
250
251 #[test]
252 fn build_request() {
253 let mut buff = [0; 40];
254 let builder = ARPSliceBuilder::new(&mut buff);
255 assert!(builder.is_ok());
256
257 let builder = builder.unwrap();
258 builder.op_code(OPCODE_REQUEST).unwrap()
259 .sender_hardware_addr(&[1, 2, 3, 4, 5, 6]).unwrap()
260 .sender_protocol_addr(&[192, 168, 0, 10]).unwrap()
261 .target_hardware_addr(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff]).unwrap()
262 .target_protocol_addr(&[192, 168, 0, 1]).unwrap();
263
264 let arp_slice = parse(&buff);
265 assert!(arp_slice.is_ok());
266
267 let arp_slice = arp_slice.unwrap();
268 assert_eq!(arp_slice.op_code(), OPCODE_REQUEST);
269
270 assert_eq!(arp_slice.sender_hardware_addr(), &[1, 2, 3, 4, 5, 6]);
271 assert_eq!(arp_slice.sender_protocol_addr(), &[192, 168, 0, 10]);
272 assert_eq!(arp_slice.target_hardware_addr(), &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
273 assert_eq!(arp_slice.target_protocol_addr(), &[192, 168, 0, 1]);
274 }
275}