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