1use net_types::ethernet::Mac;
8use net_types::ip::{Ip, IpVersion, Ipv4, Ipv6};
9use packet::{
10 BufferView, BufferViewMut, FragmentedBytesMut, PacketBuilder, PacketConstraints,
11 ParsablePacket, ParseMetadata, SerializeTarget,
12};
13use zerocopy::byteorder::network_endian::{U16, U32};
14use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
15
16use crate::error::{ParseError, ParseResult};
17
18const ETHERNET_MIN_ILLEGAL_ETHERTYPE: u16 = 1501;
19const ETHERNET_MAX_ILLEGAL_ETHERTYPE: u16 = 1535;
20
21create_protocol_enum!(
22 #[allow(missing_docs)]
24 #[derive(Copy, Clone, Hash, Eq, PartialEq)]
25 pub enum EtherType: u16 {
26 Ipv4, 0x0800, "IPv4";
27 Arp, 0x0806, "ARP";
28 Ipv6, 0x86DD, "IPv6";
29 _, "EtherType {}";
30 }
31);
32
33impl EtherType {
34 pub fn from_ip_version(ip_version: IpVersion) -> Self {
36 match ip_version {
37 IpVersion::V4 => EtherType::Ipv4,
38 IpVersion::V6 => EtherType::Ipv6,
39 }
40 }
41}
42
43pub trait EthernetIpExt: Ip {
45 const ETHER_TYPE: EtherType;
47}
48
49impl EthernetIpExt for Ipv4 {
50 const ETHER_TYPE: EtherType = EtherType::Ipv4;
51}
52
53impl EthernetIpExt for Ipv6 {
54 const ETHER_TYPE: EtherType = EtherType::Ipv6;
55}
56
57#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
58#[repr(C)]
59struct HeaderPrefix {
60 dst_mac: Mac,
61 src_mac: Mac,
62}
63
64const TPID_8021Q: u16 = 0x8100;
65const TPID_8021AD: u16 = 0x88a8;
66
67pub struct EthernetFrame<B> {
73 hdr_prefix: Ref<B, HeaderPrefix>,
74 tag: Option<Ref<B, U32>>,
75 ethertype: Ref<B, U16>,
76 body: B,
77}
78
79#[derive(PartialEq)]
85pub enum EthernetFrameLengthCheck {
86 Check,
90 NoCheck,
94}
95
96impl<B: SplitByteSlice> ParsablePacket<B, EthernetFrameLengthCheck> for EthernetFrame<B> {
97 type Error = ParseError;
98
99 fn parse_metadata(&self) -> ParseMetadata {
100 let header_len = Ref::bytes(&self.hdr_prefix).len()
101 + self.tag.as_ref().map(|tag| Ref::bytes(tag).len()).unwrap_or(0)
102 + Ref::bytes(&self.ethertype).len();
103 ParseMetadata::from_packet(header_len, self.body.len(), 0)
104 }
105
106 fn parse<BV: BufferView<B>>(
107 mut buffer: BV,
108 length_check: EthernetFrameLengthCheck,
109 ) -> ParseResult<Self> {
110 let hdr_prefix = buffer
113 .take_obj_front::<HeaderPrefix>()
114 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
115 if length_check == EthernetFrameLengthCheck::Check && buffer.len() < 48 {
116 return debug_err!(Err(ParseError::Format), "too few bytes for frame");
121 }
122
123 let ethertype_or_tpid = buffer
130 .peek_obj_front::<U16>()
131 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?
132 .get();
133 let (tag, ethertype, body) = match ethertype_or_tpid {
134 self::TPID_8021Q | self::TPID_8021AD => (
135 Some(
136 buffer.take_obj_front().ok_or_else(debug_err_fn!(
137 ParseError::Format,
138 "too few bytes for header"
139 ))?,
140 ),
141 buffer
142 .take_obj_front()
143 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?,
144 buffer.into_rest(),
145 ),
146 _ => (
147 None,
148 buffer
149 .take_obj_front()
150 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?,
151 buffer.into_rest(),
152 ),
153 };
154
155 let frame = EthernetFrame { hdr_prefix, tag, ethertype, body };
156 let et = frame.ethertype.get();
157 if (ETHERNET_MIN_ILLEGAL_ETHERTYPE..=ETHERNET_MAX_ILLEGAL_ETHERTYPE).contains(&et)
158 || (et < ETHERNET_MIN_ILLEGAL_ETHERTYPE && et as usize != frame.body.len())
159 {
160 return debug_err!(Err(ParseError::Format), "invalid ethertype number: {:x}", et);
163 }
164 Ok(frame)
165 }
166}
167
168impl<B: SplitByteSlice> EthernetFrame<B> {
169 pub fn body(&self) -> &[u8] {
171 &self.body
172 }
173
174 pub fn into_body(self) -> B
176 where
177 B: Copy,
178 {
179 self.body
180 }
181
182 pub fn src_mac(&self) -> Mac {
184 self.hdr_prefix.src_mac
185 }
186
187 pub fn dst_mac(&self) -> Mac {
189 self.hdr_prefix.dst_mac
190 }
191
192 pub fn ethertype(&self) -> Option<EtherType> {
198 let et = self.ethertype.get();
199 if et < ETHERNET_MIN_ILLEGAL_ETHERTYPE {
200 return None;
201 }
202 debug_assert!(et > ETHERNET_MAX_ILLEGAL_ETHERTYPE);
205 Some(EtherType::from(et))
206 }
207
208 fn header_len(&self) -> usize {
210 Ref::bytes(&self.hdr_prefix).len()
211 + self.tag.as_ref().map(|t| Ref::bytes(t).len()).unwrap_or(0)
212 + Ref::bytes(&self.ethertype).len()
213 }
214
215 #[allow(dead_code)]
220 fn total_frame_len(&self) -> usize {
221 self.header_len() + self.body.len()
222 }
223
224 pub fn builder(&self) -> EthernetFrameBuilder {
226 EthernetFrameBuilder {
227 src_mac: self.src_mac(),
228 dst_mac: self.dst_mac(),
229 ethertype: self.ethertype.get(),
230 min_body_len: ETHERNET_MIN_BODY_LEN_NO_TAG,
231 }
232 }
233}
234
235#[derive(Debug, Clone)]
240pub struct EthernetFrameBuilder {
241 src_mac: Mac,
242 dst_mac: Mac,
243 ethertype: u16,
244 min_body_len: usize,
245}
246
247impl EthernetFrameBuilder {
248 pub fn new(
257 src_mac: Mac,
258 dst_mac: Mac,
259 ethertype: EtherType,
260 min_body_len: usize,
261 ) -> EthernetFrameBuilder {
262 EthernetFrameBuilder { src_mac, dst_mac, ethertype: ethertype.into(), min_body_len }
263 }
264
265 pub fn src_mac(&self) -> Mac {
267 self.src_mac
268 }
269
270 pub fn dst_mac(&self) -> Mac {
272 self.dst_mac
273 }
274}
275
276impl PacketBuilder for EthernetFrameBuilder {
282 fn constraints(&self) -> PacketConstraints {
283 PacketConstraints::new(ETHERNET_HDR_LEN_NO_TAG, 0, self.min_body_len, core::usize::MAX)
284 }
285
286 fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
287 let total_len = target.header.len() + body.len();
292 let mut header = &mut target.header;
294
295 header
296 .write_obj_front(&HeaderPrefix { src_mac: self.src_mac, dst_mac: self.dst_mac })
297 .expect("too few bytes for Ethernet header");
298 header
299 .write_obj_front(&U16::new(self.ethertype))
300 .expect("too few bytes for Ethernet header");
301
302 let min_frame_size = self.min_body_len + ETHERNET_HDR_LEN_NO_TAG;
305
306 assert!(
309 total_len >= min_frame_size,
310 "total frame size of {} bytes is below minimum frame size of {}",
311 total_len,
312 min_frame_size,
313 );
314 }
315}
316
317pub const ETHERNET_HDR_LEN_NO_TAG: usize = 14;
319
320pub const ETHERNET_MIN_BODY_LEN_NO_TAG: usize = 46;
322
323pub mod testutil {
325 pub use super::{ETHERNET_HDR_LEN_NO_TAG, ETHERNET_MIN_BODY_LEN_NO_TAG};
326
327 pub const ETHERNET_DST_MAC_BYTE_OFFSET: usize = 0;
329
330 pub const ETHERNET_SRC_MAC_BYTE_OFFSET: usize = 6;
333}
334
335#[cfg(test)]
336mod tests {
337 use byteorder::{ByteOrder, NetworkEndian};
338 use packet::{
339 AsFragmentedByteSlice, Buf, GrowBufferMut, InnerPacketBuilder, ParseBuffer, Serializer,
340 };
341
342 use super::*;
343
344 const DEFAULT_DST_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
345 const DEFAULT_SRC_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
346 const ETHERNET_ETHERTYPE_BYTE_OFFSET: usize = 12;
347 const ETHERNET_MIN_FRAME_LEN: usize = 60;
348
349 fn new_parse_buf() -> ([u8; ETHERNET_MIN_FRAME_LEN], [u8; ETHERNET_MIN_BODY_LEN_NO_TAG]) {
353 let mut buf = [0; ETHERNET_MIN_FRAME_LEN];
354 for (i, elem) in buf.iter_mut().enumerate() {
355 *elem = i as u8;
356 }
357 NetworkEndian::write_u16(&mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..], EtherType::Arp.into());
358 let mut body = [0; ETHERNET_MIN_BODY_LEN_NO_TAG];
359 (&mut body).copy_from_slice(&buf[ETHERNET_HDR_LEN_NO_TAG..]);
360 (buf, body)
361 }
362
363 fn new_serialize_buf() -> [u8; ETHERNET_MIN_BODY_LEN_NO_TAG] {
366 let mut buf = [0; ETHERNET_MIN_BODY_LEN_NO_TAG];
367 for (i, elem) in buf.iter_mut().enumerate() {
368 *elem = i as u8;
369 }
370 buf
371 }
372
373 #[test]
374 fn test_parse() {
375 crate::testutil::set_logger_for_test();
376 let (mut backing_buf, body) = new_parse_buf();
377 let mut buf = &mut backing_buf[..];
378 let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
380 assert_eq!(frame.hdr_prefix.dst_mac, DEFAULT_DST_MAC);
381 assert_eq!(frame.hdr_prefix.src_mac, DEFAULT_SRC_MAC);
382 assert!(frame.tag.is_none());
383 assert_eq!(frame.ethertype(), Some(EtherType::Arp));
384 assert_eq!(frame.body(), &body[..]);
385 let mut buf = &mut backing_buf[..ETHERNET_HDR_LEN_NO_TAG];
387 let frame =
388 buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck).unwrap();
389 assert_eq!(frame.hdr_prefix.dst_mac, DEFAULT_DST_MAC);
390 assert_eq!(frame.hdr_prefix.src_mac, DEFAULT_SRC_MAC);
391 assert!(frame.tag.is_none());
392 assert_eq!(frame.ethertype(), Some(EtherType::Arp));
393 assert_eq!(frame.body(), &[]);
394
395 for tpid in [TPID_8021Q, TPID_8021AD].iter() {
399 let (mut buf, body) = new_parse_buf();
400 let mut buf = &mut buf[..];
401
402 const TPID_OFFSET: usize = 12;
403 NetworkEndian::write_u16(&mut buf[TPID_OFFSET..], *tpid);
404 NetworkEndian::write_u16(&mut buf[TPID_OFFSET + 4..], EtherType::Arp.into());
406
407 let frame =
408 buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
409 assert_eq!(frame.hdr_prefix.dst_mac, DEFAULT_DST_MAC);
410 assert_eq!(frame.hdr_prefix.src_mac, DEFAULT_SRC_MAC);
411 assert_eq!(frame.ethertype(), Some(EtherType::Arp));
412
413 let tag: &U32 = frame.tag.as_ref().unwrap();
415 let want_tag =
416 u32::from(*tpid) << 16 | ((TPID_OFFSET as u32 + 2) << 8) | (TPID_OFFSET as u32 + 3);
417 assert_eq!(tag.get(), want_tag);
418 assert_eq!(frame.body(), &body[4..]);
421 }
422 }
423
424 #[test]
425 fn test_ethertype() {
426 let mut buf = [0u8; 1014];
428 NetworkEndian::write_u16(&mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..], 1001);
430 assert!((&mut buf[..])
431 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
432 .is_err());
433
434 NetworkEndian::write_u16(&mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..], 1000);
436 assert_eq!(
437 (&mut buf[..])
438 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
439 .unwrap()
440 .ethertype(),
441 None
442 );
443
444 let mut buf = [0u8; 1014];
446 NetworkEndian::write_u16(
447 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
448 ETHERNET_MAX_ILLEGAL_ETHERTYPE + 1,
449 );
450 assert_eq!(
451 (&mut buf[..])
452 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
453 .unwrap()
454 .ethertype(),
455 Some(EtherType::Other(ETHERNET_MAX_ILLEGAL_ETHERTYPE + 1))
456 );
457 }
458
459 #[test]
460 fn test_serialize() {
461 let buf = (&new_serialize_buf()[..])
462 .into_serializer()
463 .encapsulate(EthernetFrameBuilder::new(
464 DEFAULT_DST_MAC,
465 DEFAULT_SRC_MAC,
466 EtherType::Arp,
467 ETHERNET_MIN_BODY_LEN_NO_TAG,
468 ))
469 .serialize_vec_outer()
470 .unwrap();
471 assert_eq!(
472 &buf.as_ref()[..ETHERNET_HDR_LEN_NO_TAG],
473 [6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 0x08, 0x06]
474 );
475 }
476
477 #[test]
478 fn test_serialize_zeroes() {
479 let mut buf_0 = [0; ETHERNET_MIN_FRAME_LEN];
482 let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], ETHERNET_HDR_LEN_NO_TAG..)
483 .encapsulate(EthernetFrameBuilder::new(
484 DEFAULT_SRC_MAC,
485 DEFAULT_DST_MAC,
486 EtherType::Arp,
487 ETHERNET_MIN_BODY_LEN_NO_TAG,
488 ))
489 .serialize_vec_outer()
490 .unwrap()
491 .unwrap_a();
492 let mut buf_1 = [0; ETHERNET_MIN_FRAME_LEN];
493 (&mut buf_1[..ETHERNET_HDR_LEN_NO_TAG]).copy_from_slice(&[0xFF; ETHERNET_HDR_LEN_NO_TAG]);
494 let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], ETHERNET_HDR_LEN_NO_TAG..)
495 .encapsulate(EthernetFrameBuilder::new(
496 DEFAULT_SRC_MAC,
497 DEFAULT_DST_MAC,
498 EtherType::Arp,
499 ETHERNET_MIN_BODY_LEN_NO_TAG,
500 ))
501 .serialize_vec_outer()
502 .unwrap()
503 .unwrap_a();
504 assert_eq!(&buf_0[..], &buf_1[..]);
505 }
506
507 #[test]
508 fn test_parse_error() {
509 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN - 1];
511 assert!((&mut buf[..])
512 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
513 .is_err());
514
515 let mut buf = [0u8; ETHERNET_HDR_LEN_NO_TAG - 1];
518 assert!((&mut buf[..])
519 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck)
520 .is_err());
521
522 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
524 NetworkEndian::write_u16(
525 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
526 ETHERNET_MIN_ILLEGAL_ETHERTYPE - 1,
527 );
528 assert!((&mut buf[..])
529 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
530 .is_err());
531
532 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
534 NetworkEndian::write_u16(
535 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
536 ETHERNET_MIN_ILLEGAL_ETHERTYPE,
537 );
538 assert!((&mut buf[..])
539 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
540 .is_err());
541
542 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
544 NetworkEndian::write_u16(
545 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
546 ETHERNET_MAX_ILLEGAL_ETHERTYPE,
547 );
548 assert!((&mut buf[..])
549 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
550 .is_err());
551 }
552
553 #[test]
554 #[should_panic(expected = "bytes is below minimum frame size of")]
555 fn test_serialize_panic() {
556 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN - 1];
558 let mut b = [&mut buf[..]];
559 let buf = b.as_fragmented_byte_slice();
560 let (header, body, footer) = buf.try_split_contiguous(ETHERNET_HDR_LEN_NO_TAG..).unwrap();
561 EthernetFrameBuilder::new(
562 Mac::new([0, 1, 2, 3, 4, 5]),
563 Mac::new([6, 7, 8, 9, 10, 11]),
564 EtherType::Arp,
565 ETHERNET_MIN_BODY_LEN_NO_TAG,
566 )
567 .serialize(&mut SerializeTarget { header, footer }, body);
568 }
569
570 #[test]
571 fn test_custom_min_body_len() {
572 const MIN_BODY_LEN: usize = 4;
573 const UNWRITTEN_BYTE: u8 = 0xAA;
574
575 let builder = EthernetFrameBuilder::new(
576 Mac::new([0, 1, 2, 3, 4, 5]),
577 Mac::new([6, 7, 8, 9, 10, 11]),
578 EtherType::Arp,
579 MIN_BODY_LEN,
580 );
581
582 let mut buffer = [UNWRITTEN_BYTE; ETHERNET_MIN_FRAME_LEN];
583 GrowBufferMut::serialize(
586 &mut Buf::new(&mut buffer[..], ETHERNET_HDR_LEN_NO_TAG..ETHERNET_HDR_LEN_NO_TAG),
587 builder,
588 );
589
590 let (header, tail) = buffer.split_at(ETHERNET_HDR_LEN_NO_TAG);
591 let (padding, unwritten) = tail.split_at(MIN_BODY_LEN);
592 assert_eq!(
593 header,
594 &[
595 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 08, 06, ]
599 );
600 assert_eq!(padding, &[0; MIN_BODY_LEN]);
601 assert_eq!(
602 unwritten,
603 &[UNWRITTEN_BYTE; ETHERNET_MIN_FRAME_LEN - MIN_BODY_LEN - ETHERNET_HDR_LEN_NO_TAG]
604 );
605 }
606}