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