1#[cfg(test)]
8use core::fmt::{self, Debug, Formatter};
9use core::hash::Hash;
10use core::mem;
11
12use net_types::ethernet::Mac;
13use net_types::ip::{IpAddress, Ipv4Addr};
14use packet::{BufferView, BufferViewMut, InnerPacketBuilder, ParsablePacket, ParseMetadata};
15use zerocopy::byteorder::network_endian::U16;
16use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
17
18use crate::error::{ParseError, ParseResult};
19
20#[cfg(test)]
21pub(crate) const ARP_HDR_LEN: usize = 8;
22#[cfg(test)]
23pub(crate) const ARP_ETHERNET_IPV4_PACKET_LEN: usize = 28;
24
25create_protocol_enum!(
26 #[derive(Copy, Clone, Eq, PartialEq)]
28 #[allow(missing_docs)]
29 pub enum ArpOp : u16 {
30 Request, 0x0001, "Request";
31 Response, 0x0002, "Response";
32 _, "ArpOp {}";
33 }
34);
35
36pub trait HType: FromBytes + IntoBytes + Immutable + Unaligned + Copy + Clone + Hash + Eq {
38 const HTYPE: ArpHardwareType;
40 const HLEN: u8;
42 const BROADCAST: Self;
44}
45
46pub trait PType: FromBytes + IntoBytes + Immutable + Unaligned + Copy + Clone + Hash + Eq {
48 const PTYPE: ArpNetworkType;
50 const PLEN: u8;
52}
53
54impl HType for Mac {
55 const HTYPE: ArpHardwareType = ArpHardwareType::Ethernet;
56 const HLEN: u8 = mem::size_of::<Mac>() as u8;
57 const BROADCAST: Mac = Mac::BROADCAST;
58}
59
60impl PType for Ipv4Addr {
61 const PTYPE: ArpNetworkType = ArpNetworkType::Ipv4;
62 const PLEN: u8 = Ipv4Addr::BYTES;
63}
64
65create_protocol_enum!(
66 #[derive(PartialEq)]
68 #[allow(missing_docs)]
69 pub enum ArpHardwareType : u16 {
70 Ethernet, 0x0001, "Ethernet";
71 }
72);
73
74create_protocol_enum!(
75 #[derive(PartialEq)]
77 #[allow(missing_docs)]
78 pub enum ArpNetworkType : u16 {
79 Ipv4, 0x0800, "IPv4";
80 }
81);
82
83#[derive(Default, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
84#[repr(C)]
85struct Header {
86 htype: U16, ptype: U16, hlen: u8, plen: u8, oper: U16, }
92
93impl Header {
94 fn new<HwAddr: HType, ProtoAddr: PType>(op: ArpOp) -> Header {
95 Header {
96 htype: U16::new(<HwAddr as HType>::HTYPE.into()),
97 hlen: <HwAddr as HType>::HLEN,
98 ptype: U16::new(<ProtoAddr as PType>::PTYPE.into()),
99 plen: <ProtoAddr as PType>::PLEN,
100 oper: U16::new(op.into()),
101 }
102 }
103}
104
105pub fn peek_arp_types<B: SplitByteSlice>(
120 bytes: B,
121) -> ParseResult<(ArpHardwareType, ArpNetworkType)> {
122 let (header, _) = Ref::<B, Header>::from_prefix(bytes).map_err(Into::into).map_err(
123 |_: zerocopy::SizeError<_, _>| debug_err!(ParseError::Format, "too few bytes for header"),
124 )?;
125
126 let hw = ArpHardwareType::try_from(header.htype.get()).ok().ok_or_else(debug_err_fn!(
127 ParseError::NotSupported,
128 "unrecognized hardware protocol: {:x}",
129 header.htype.get()
130 ))?;
131 let proto = ArpNetworkType::try_from(header.ptype.get()).ok().ok_or_else(debug_err_fn!(
132 ParseError::NotSupported,
133 "unrecognized network protocol: {:x}",
134 header.ptype.get()
135 ))?;
136 let hlen = match hw {
137 ArpHardwareType::Ethernet => <Mac as HType>::HLEN,
138 };
139 let plen = match proto {
140 ArpNetworkType::Ipv4 => <Ipv4Addr as PType>::PLEN,
141 };
142 if header.hlen != hlen || header.plen != plen {
143 return debug_err!(
144 Err(ParseError::Format),
145 "unexpected hardware or protocol address length for protocol {:?}",
146 proto
147 );
148 }
149 Ok((hw, proto))
150}
151
152#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
156#[repr(C)]
157struct Body<HwAddr, ProtoAddr> {
158 sha: HwAddr,
159 spa: ProtoAddr,
160 tha: HwAddr,
161 tpa: ProtoAddr,
162}
163
164pub struct ArpPacket<B, HwAddr, ProtoAddr> {
170 header: Ref<B, Header>,
171 body: Ref<B, Body<HwAddr, ProtoAddr>>,
172}
173
174impl<B: SplitByteSlice, HwAddr, ProtoAddr> ParsablePacket<B, ()> for ArpPacket<B, HwAddr, ProtoAddr>
175where
176 HwAddr: Copy + HType + FromBytes + KnownLayout + Unaligned,
177 ProtoAddr: Copy + PType + FromBytes + KnownLayout + Unaligned,
178{
179 type Error = ParseError;
180
181 fn parse_metadata(&self) -> ParseMetadata {
182 ParseMetadata::from_inner_packet(
183 Ref::bytes(&self.header).len() + Ref::bytes(&self.body).len(),
184 )
185 }
186
187 fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> ParseResult<Self> {
188 let header = buffer
189 .take_obj_front::<Header>()
190 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
191 let body = buffer
192 .take_obj_front::<Body<HwAddr, ProtoAddr>>()
193 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for body"))?;
194 let _: B = buffer.take_rest_front();
196
197 if header.htype.get() != <HwAddr as HType>::HTYPE.into()
198 || header.ptype.get() != <ProtoAddr as PType>::PTYPE.into()
199 {
200 return debug_err!(
201 Err(ParseError::NotExpected),
202 "unexpected hardware or network protocols"
203 );
204 }
205 if header.hlen != <HwAddr as HType>::HLEN || header.plen != <ProtoAddr as PType>::PLEN {
206 return debug_err!(
207 Err(ParseError::Format),
208 "unexpected hardware or protocol address length"
209 );
210 }
211
212 if let ArpOp::Other(x) = header.oper.get().into() {
213 return debug_err!(Err(ParseError::Format), "unrecognized op code: {:x}", x);
214 }
215
216 Ok(ArpPacket { header, body })
217 }
218}
219
220impl<B: SplitByteSlice, HwAddr, ProtoAddr> ArpPacket<B, HwAddr, ProtoAddr>
221where
222 HwAddr: Copy + HType + FromBytes + KnownLayout + Immutable + Unaligned,
223 ProtoAddr: Copy + PType + FromBytes + KnownLayout + Immutable + Unaligned,
224{
225 pub fn operation(&self) -> ArpOp {
227 self.header.oper.get().into()
228 }
229
230 pub fn sender_hardware_address(&self) -> HwAddr {
232 self.body.sha
233 }
234
235 pub fn sender_protocol_address(&self) -> ProtoAddr {
237 self.body.spa
238 }
239
240 pub fn target_hardware_address(&self) -> HwAddr {
242 self.body.tha
243 }
244
245 pub fn target_protocol_address(&self) -> ProtoAddr {
247 self.body.tpa
248 }
249
250 pub fn builder(&self) -> ArpPacketBuilder<HwAddr, ProtoAddr> {
252 ArpPacketBuilder {
253 op: self.operation(),
254 sha: self.sender_hardware_address(),
255 spa: self.sender_protocol_address(),
256 tha: self.target_hardware_address(),
257 tpa: self.target_protocol_address(),
258 }
259 }
260}
261
262#[derive(Debug)]
264pub struct ArpPacketBuilder<HwAddr, ProtoAddr> {
265 op: ArpOp,
266 sha: HwAddr,
267 spa: ProtoAddr,
268 tha: HwAddr,
269 tpa: ProtoAddr,
270}
271
272impl<HwAddr, ProtoAddr> ArpPacketBuilder<HwAddr, ProtoAddr> {
273 pub fn new(
275 operation: ArpOp,
276 sender_hardware_addr: HwAddr,
277 sender_protocol_addr: ProtoAddr,
278 target_hardware_addr: HwAddr,
279 target_protocol_addr: ProtoAddr,
280 ) -> ArpPacketBuilder<HwAddr, ProtoAddr> {
281 ArpPacketBuilder {
282 op: operation,
283 sha: sender_hardware_addr,
284 spa: sender_protocol_addr,
285 tha: target_hardware_addr,
286 tpa: target_protocol_addr,
287 }
288 }
289}
290
291impl<HwAddr, ProtoAddr> InnerPacketBuilder for ArpPacketBuilder<HwAddr, ProtoAddr>
292where
293 HwAddr: Copy + HType + FromBytes + IntoBytes + Immutable + Unaligned,
294 ProtoAddr: Copy + PType + FromBytes + IntoBytes + Immutable + Unaligned,
295{
296 fn bytes_len(&self) -> usize {
297 mem::size_of::<Header>() + mem::size_of::<Body<HwAddr, ProtoAddr>>()
298 }
299
300 fn serialize(&self, mut buffer: &mut [u8]) {
301 let mut buffer = &mut buffer;
303 buffer
304 .write_obj_front(&Header::new::<HwAddr, ProtoAddr>(self.op))
305 .expect("too few bytes for ARP packet");
306 buffer
307 .write_obj_front(&Body { sha: self.sha, spa: self.spa, tha: self.tha, tpa: self.tpa })
308 .expect("too few bytes for ARP packet");
309 }
310}
311
312#[cfg(test)]
313impl<B, HwAddr, ProtoAddr> Debug for ArpPacket<B, HwAddr, ProtoAddr> {
314 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
315 write!(fmt, "ArpPacket")
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use packet::{ParseBuffer, Serializer};
322
323 use super::*;
324 use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
325 use crate::testutil::*;
326
327 const TEST_SENDER_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
328 const TEST_TARGET_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
329 const TEST_SENDER_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
330 const TEST_TARGET_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
331
332 #[test]
333 fn test_parse_serialize_full() {
334 use crate::testdata::arp_request::*;
335
336 let mut buf = ETHERNET_FRAME.bytes;
337 let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
338 verify_ethernet_frame(&frame, ETHERNET_FRAME);
339
340 let (hw, proto) = peek_arp_types(frame.body()).unwrap();
341 assert_eq!(hw, ArpHardwareType::Ethernet);
342 assert_eq!(proto, ArpNetworkType::Ipv4);
343
344 let mut body = frame.body();
345 let arp = body.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
346 assert_eq!(arp.operation(), ARP_OPERATION);
347 assert_eq!(frame.src_mac(), arp.sender_hardware_address());
348
349 let frame_bytes = arp
350 .builder()
351 .into_serializer()
352 .encapsulate(frame.builder())
353 .serialize_vec_outer()
354 .unwrap();
355 assert_eq!(frame_bytes.as_ref(), ETHERNET_FRAME.bytes);
356 }
357
358 fn header_to_bytes(header: Header) -> [u8; ARP_HDR_LEN] {
359 zerocopy::transmute!(header)
360 }
361
362 fn new_header() -> Header {
364 Header::new::<Mac, Ipv4Addr>(ArpOp::Request)
365 }
366
367 #[test]
368 fn test_peek() {
369 let header = new_header();
370 let (hw, proto) = peek_arp_types(&header_to_bytes(header)[..]).unwrap();
371 assert_eq!(hw, ArpHardwareType::Ethernet);
372 assert_eq!(proto, ArpNetworkType::Ipv4);
373
374 let mut header = new_header();
377 header.oper = U16::new(3);
378 let (hw, proto) = peek_arp_types(&header_to_bytes(header)[..]).unwrap();
379 assert_eq!(hw, ArpHardwareType::Ethernet);
380 assert_eq!(proto, ArpNetworkType::Ipv4);
381 }
382
383 #[test]
384 fn test_parse() {
385 let mut buf = &mut [
386 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 5, 6, 7, 8,
387 ][..];
388 (&mut buf[..ARP_HDR_LEN]).copy_from_slice(&header_to_bytes(new_header()));
389 let (hw, proto) = peek_arp_types(&buf[..]).unwrap();
390 assert_eq!(hw, ArpHardwareType::Ethernet);
391 assert_eq!(proto, ArpNetworkType::Ipv4);
392
393 let buf = &mut buf;
394 let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
395 assert_eq!(packet.sender_hardware_address(), TEST_SENDER_MAC);
396 assert_eq!(packet.sender_protocol_address(), TEST_SENDER_IPV4);
397 assert_eq!(packet.target_hardware_address(), TEST_TARGET_MAC);
398 assert_eq!(packet.target_protocol_address(), TEST_TARGET_IPV4);
399 assert_eq!(packet.operation(), ArpOp::Request);
400 }
401
402 #[test]
403 fn test_serialize() {
404 let mut buf = ArpPacketBuilder::new(
405 ArpOp::Request,
406 TEST_SENDER_MAC,
407 TEST_SENDER_IPV4,
408 TEST_TARGET_MAC,
409 TEST_TARGET_IPV4,
410 )
411 .into_serializer()
412 .serialize_vec_outer()
413 .unwrap();
414 assert_eq!(
415 AsRef::<[u8]>::as_ref(&buf),
416 &[0, 1, 8, 0, 6, 4, 0, 1, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 5, 6, 7, 8,]
417 );
418 let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
419 assert_eq!(packet.sender_hardware_address(), TEST_SENDER_MAC);
420 assert_eq!(packet.sender_protocol_address(), TEST_SENDER_IPV4);
421 assert_eq!(packet.target_hardware_address(), TEST_TARGET_MAC);
422 assert_eq!(packet.target_protocol_address(), TEST_TARGET_IPV4);
423 assert_eq!(packet.operation(), ArpOp::Request);
424 }
425
426 #[test]
427 fn test_peek_error() {
428 let buf = [0; ARP_HDR_LEN - 1];
430 assert_eq!(peek_arp_types(&buf[..]).unwrap_err(), ParseError::Format);
431
432 let mut header = new_header();
434 header.htype = U16::ZERO;
435 assert_eq!(
436 peek_arp_types(&header_to_bytes(header)[..]).unwrap_err(),
437 ParseError::NotSupported
438 );
439
440 let mut header = new_header();
442 header.ptype = U16::ZERO;
443 assert_eq!(
444 peek_arp_types(&header_to_bytes(header)[..]).unwrap_err(),
445 ParseError::NotSupported
446 );
447
448 let mut header = new_header();
450 header.hlen = 7;
451 assert_eq!(peek_arp_types(&header_to_bytes(header)[..]).unwrap_err(), ParseError::Format);
452
453 let mut header = new_header();
455 header.plen = 5;
456 assert_eq!(peek_arp_types(&header_to_bytes(header)[..]).unwrap_err(), ParseError::Format);
457 }
458
459 #[test]
460 fn test_parse_error() {
461 fn assert_err(mut buf: &[u8], err: ParseError) {
463 assert_eq!(buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap_err(), err);
464 }
465
466 fn assert_header_err(header: Header, err: ParseError) {
468 let mut buf = [0; ARP_ETHERNET_IPV4_PACKET_LEN];
469 *Ref::<_, Header>::from_prefix(&mut buf[..]).unwrap().0 = header;
470 assert_err(&buf[..], err);
471 }
472
473 let buf = [0; ARP_ETHERNET_IPV4_PACKET_LEN - 1];
475 assert_err(&buf[..], ParseError::Format);
476
477 let mut header = new_header();
479 header.htype = U16::ZERO;
480 assert_header_err(header, ParseError::NotExpected);
481
482 let mut header = new_header();
484 header.ptype = U16::ZERO;
485 assert_header_err(header, ParseError::NotExpected);
486
487 let mut header = new_header();
489 header.hlen = 7;
490 assert_header_err(header, ParseError::Format);
491
492 let mut header = new_header();
494 header.plen = 5;
495 assert_header_err(header, ParseError::Format);
496
497 let mut header = new_header();
499 header.oper = U16::new(3);
500 assert_header_err(header, ParseError::Format);
501 }
502
503 #[test]
504 fn test_serialize_zeroes() {
505 let mut buf_0 = [0; ARP_ETHERNET_IPV4_PACKET_LEN];
508 ArpPacketBuilder::new(
509 ArpOp::Request,
510 TEST_SENDER_MAC,
511 TEST_SENDER_IPV4,
512 TEST_TARGET_MAC,
513 TEST_TARGET_IPV4,
514 )
515 .serialize(&mut buf_0[..]);
516 let mut buf_1 = [0xFF; ARP_ETHERNET_IPV4_PACKET_LEN];
517 ArpPacketBuilder::new(
518 ArpOp::Request,
519 TEST_SENDER_MAC,
520 TEST_SENDER_IPV4,
521 TEST_TARGET_MAC,
522 TEST_TARGET_IPV4,
523 )
524 .serialize(&mut buf_1[..]);
525 assert_eq!(buf_0, buf_1);
526 }
527
528 #[test]
529 #[should_panic(expected = "too few bytes for ARP packet")]
530 fn test_serialize_panic_insufficient_packet_space() {
531 ArpPacketBuilder::new(
534 ArpOp::Request,
535 TEST_SENDER_MAC,
536 TEST_SENDER_IPV4,
537 TEST_TARGET_MAC,
538 TEST_TARGET_IPV4,
539 )
540 .serialize(&mut [0; ARP_ETHERNET_IPV4_PACKET_LEN - 1]);
541 }
542}