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 pub fn to_ip_version(self) -> Option<IpVersion> {
45 match self {
46 EtherType::Ipv4 => Some(IpVersion::V4),
47 EtherType::Ipv6 => Some(IpVersion::V6),
48 _ => None,
49 }
50 }
51}
52
53pub trait EthernetIpExt: Ip {
55 const ETHER_TYPE: EtherType;
57}
58
59impl EthernetIpExt for Ipv4 {
60 const ETHER_TYPE: EtherType = EtherType::Ipv4;
61}
62
63impl EthernetIpExt for Ipv6 {
64 const ETHER_TYPE: EtherType = EtherType::Ipv6;
65}
66
67#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
68#[repr(C)]
69struct HeaderPrefix {
70 dst_mac: Mac,
71 src_mac: Mac,
72}
73
74const TPID_8021Q: u16 = 0x8100;
75const TPID_8021AD: u16 = 0x88a8;
76
77pub struct EthernetFrame<B> {
83 hdr_prefix: Ref<B, HeaderPrefix>,
84 tag: Option<Ref<B, U32>>,
85 ethertype: Ref<B, U16>,
86 body: B,
87}
88
89#[derive(PartialEq)]
95pub enum EthernetFrameLengthCheck {
96 Check,
100 NoCheck,
104}
105
106impl<B: SplitByteSlice> ParsablePacket<B, EthernetFrameLengthCheck> for EthernetFrame<B> {
107 type Error = ParseError;
108
109 fn parse_metadata(&self) -> ParseMetadata {
110 let header_len = Ref::bytes(&self.hdr_prefix).len()
111 + self.tag.as_ref().map(|tag| Ref::bytes(tag).len()).unwrap_or(0)
112 + Ref::bytes(&self.ethertype).len();
113 ParseMetadata::from_packet(header_len, self.body.len(), 0)
114 }
115
116 fn parse<BV: BufferView<B>>(
117 mut buffer: BV,
118 length_check: EthernetFrameLengthCheck,
119 ) -> ParseResult<Self> {
120 let hdr_prefix = buffer
123 .take_obj_front::<HeaderPrefix>()
124 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
125 if length_check == EthernetFrameLengthCheck::Check && buffer.len() < 48 {
126 return debug_err!(Err(ParseError::Format), "too few bytes for frame");
131 }
132
133 let ethertype_or_tpid = buffer
140 .peek_obj_front::<U16>()
141 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?
142 .get();
143 let (tag, ethertype, body) = match ethertype_or_tpid {
144 self::TPID_8021Q | self::TPID_8021AD => (
145 Some(
146 buffer.take_obj_front().ok_or_else(debug_err_fn!(
147 ParseError::Format,
148 "too few bytes for header"
149 ))?,
150 ),
151 buffer
152 .take_obj_front()
153 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?,
154 buffer.into_rest(),
155 ),
156 _ => (
157 None,
158 buffer
159 .take_obj_front()
160 .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?,
161 buffer.into_rest(),
162 ),
163 };
164
165 let frame = EthernetFrame { hdr_prefix, tag, ethertype, body };
166 let et = frame.ethertype.get();
167 if (ETHERNET_MIN_ILLEGAL_ETHERTYPE..=ETHERNET_MAX_ILLEGAL_ETHERTYPE).contains(&et)
168 || (et < ETHERNET_MIN_ILLEGAL_ETHERTYPE && et as usize != frame.body.len())
169 {
170 return debug_err!(Err(ParseError::Format), "invalid ethertype number: {:x}", et);
173 }
174 Ok(frame)
175 }
176}
177
178impl<B: SplitByteSlice> EthernetFrame<B> {
179 pub fn body(&self) -> &[u8] {
181 &self.body
182 }
183
184 pub fn into_body(self) -> B
186 where
187 B: Copy,
188 {
189 self.body
190 }
191
192 pub fn src_mac(&self) -> Mac {
194 self.hdr_prefix.src_mac
195 }
196
197 pub fn dst_mac(&self) -> Mac {
199 self.hdr_prefix.dst_mac
200 }
201
202 pub fn tag(&self) -> Option<u32> {
204 self.tag.as_ref().map(|t| t.get())
205 }
206
207 pub fn ethertype(&self) -> Option<EtherType> {
213 let et = self.ethertype.get();
214 if et < ETHERNET_MIN_ILLEGAL_ETHERTYPE {
215 return None;
216 }
217 debug_assert!(et > ETHERNET_MAX_ILLEGAL_ETHERTYPE);
220 Some(EtherType::from(et))
221 }
222
223 fn header_len(&self) -> usize {
225 Ref::bytes(&self.hdr_prefix).len()
226 + self.tag.as_ref().map(|t| Ref::bytes(t).len()).unwrap_or(0)
227 + Ref::bytes(&self.ethertype).len()
228 }
229
230 #[allow(dead_code)]
235 fn total_frame_len(&self) -> usize {
236 self.header_len() + self.body.len()
237 }
238
239 pub fn builder(&self) -> EthernetFrameBuilder {
241 EthernetFrameBuilder {
242 src_mac: self.src_mac(),
243 dst_mac: self.dst_mac(),
244 ethertype: self.ethertype.get(),
245 min_body_len: ETHERNET_MIN_BODY_LEN_NO_TAG,
246 }
247 }
248}
249
250#[derive(Debug, Clone)]
255pub struct EthernetFrameBuilder {
256 src_mac: Mac,
257 dst_mac: Mac,
258 ethertype: u16,
259 min_body_len: usize,
260}
261
262impl EthernetFrameBuilder {
263 pub fn new(
272 src_mac: Mac,
273 dst_mac: Mac,
274 ethertype: EtherType,
275 min_body_len: usize,
276 ) -> EthernetFrameBuilder {
277 EthernetFrameBuilder { src_mac, dst_mac, ethertype: ethertype.into(), min_body_len }
278 }
279
280 pub fn src_mac(&self) -> Mac {
282 self.src_mac
283 }
284
285 pub fn dst_mac(&self) -> Mac {
287 self.dst_mac
288 }
289}
290
291pub struct EthernetEnvelope;
298
299pub trait EthernetSerializationContext: SerializationContext {
301 fn envelope_to_state(envelope: EthernetEnvelope) -> Self::ContextState;
303}
304
305impl EthernetSerializationContext for NoOpSerializationContext {
306 fn envelope_to_state(_envelope: EthernetEnvelope) -> Self::ContextState {
307 ()
308 }
309}
310
311impl NestablePacketBuilder for EthernetFrameBuilder {
312 fn constraints(&self) -> PacketConstraints {
313 PacketConstraints::new(ETHERNET_HDR_LEN_NO_TAG, 0, self.min_body_len, usize::MAX)
314 }
315}
316
317impl<C: EthernetSerializationContext> PacketBuilder<C> for EthernetFrameBuilder {
318 fn context_state(&self) -> C::ContextState {
319 C::envelope_to_state(EthernetEnvelope)
320 }
321
322 fn serialize(
323 &self,
324 _context: &mut C,
325 target: &mut SerializeTarget<'_>,
326 body: FragmentedBytesMut<'_, '_>,
327 ) {
328 let total_len = target.header.len() + body.len();
333 let mut header = &mut target.header;
335
336 header
337 .write_obj_front(&HeaderPrefix { src_mac: self.src_mac, dst_mac: self.dst_mac })
338 .expect("too few bytes for Ethernet header");
339 header
340 .write_obj_front(&U16::new(self.ethertype))
341 .expect("too few bytes for Ethernet header");
342
343 let min_frame_size = self.min_body_len + ETHERNET_HDR_LEN_NO_TAG;
346
347 assert!(
350 total_len >= min_frame_size,
351 "total frame size of {} bytes is below minimum frame size of {}",
352 total_len,
353 min_frame_size,
354 );
355 }
356}
357
358pub const ETHERNET_HDR_LEN_NO_TAG: usize = 14;
360
361pub const ETHERNET_MIN_BODY_LEN_NO_TAG: usize = 46;
363
364pub mod testutil {
366 pub use super::{ETHERNET_HDR_LEN_NO_TAG, ETHERNET_MIN_BODY_LEN_NO_TAG};
367
368 pub const ETHERNET_DST_MAC_BYTE_OFFSET: usize = 0;
370
371 pub const ETHERNET_SRC_MAC_BYTE_OFFSET: usize = 6;
374}
375
376#[cfg(test)]
377mod tests {
378 use byteorder::{ByteOrder, NetworkEndian};
379 use packet::{
380 AsFragmentedByteSlice, Buf, GrowBufferMut, InnerPacketBuilder, NoOpSerializationContext,
381 ParseBuffer, Serializer,
382 };
383
384 use super::*;
385
386 const DEFAULT_DST_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
387 const DEFAULT_SRC_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
388 const ETHERNET_ETHERTYPE_BYTE_OFFSET: usize = 12;
389 const ETHERNET_MIN_FRAME_LEN: usize = 60;
390
391 fn new_parse_buf() -> ([u8; ETHERNET_MIN_FRAME_LEN], [u8; ETHERNET_MIN_BODY_LEN_NO_TAG]) {
395 let mut buf = [0; ETHERNET_MIN_FRAME_LEN];
396 for (i, elem) in buf.iter_mut().enumerate() {
397 *elem = i as u8;
398 }
399 NetworkEndian::write_u16(&mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..], EtherType::Arp.into());
400 let mut body = [0; ETHERNET_MIN_BODY_LEN_NO_TAG];
401 (&mut body).copy_from_slice(&buf[ETHERNET_HDR_LEN_NO_TAG..]);
402 (buf, body)
403 }
404
405 fn new_serialize_buf() -> [u8; ETHERNET_MIN_BODY_LEN_NO_TAG] {
408 let mut buf = [0; ETHERNET_MIN_BODY_LEN_NO_TAG];
409 for (i, elem) in buf.iter_mut().enumerate() {
410 *elem = i as u8;
411 }
412 buf
413 }
414
415 #[test]
416 fn test_parse() {
417 crate::testutil::set_logger_for_test();
418 let (mut backing_buf, body) = new_parse_buf();
419 let mut buf = &mut backing_buf[..];
420 let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
422 assert_eq!(frame.hdr_prefix.dst_mac, DEFAULT_DST_MAC);
423 assert_eq!(frame.hdr_prefix.src_mac, DEFAULT_SRC_MAC);
424 assert!(frame.tag.is_none());
425 assert_eq!(frame.tag(), None);
426 assert_eq!(frame.ethertype(), Some(EtherType::Arp));
427 assert_eq!(frame.body(), &body[..]);
428 let mut buf = &mut backing_buf[..ETHERNET_HDR_LEN_NO_TAG];
430 let frame =
431 buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck).unwrap();
432 assert_eq!(frame.hdr_prefix.dst_mac, DEFAULT_DST_MAC);
433 assert_eq!(frame.hdr_prefix.src_mac, DEFAULT_SRC_MAC);
434 assert!(frame.tag.is_none());
435 assert_eq!(frame.tag(), None);
436 assert_eq!(frame.ethertype(), Some(EtherType::Arp));
437 assert_eq!(frame.body(), &[]);
438
439 for tpid in [TPID_8021Q, TPID_8021AD].iter() {
443 let (mut buf, body) = new_parse_buf();
444 let mut buf = &mut buf[..];
445
446 const TPID_OFFSET: usize = 12;
447 NetworkEndian::write_u16(&mut buf[TPID_OFFSET..], *tpid);
448 NetworkEndian::write_u16(&mut buf[TPID_OFFSET + 4..], EtherType::Arp.into());
450
451 let frame =
452 buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
453 assert_eq!(frame.hdr_prefix.dst_mac, DEFAULT_DST_MAC);
454 assert_eq!(frame.hdr_prefix.src_mac, DEFAULT_SRC_MAC);
455 assert_eq!(frame.ethertype(), Some(EtherType::Arp));
456
457 let want_tag =
458 u32::from(*tpid) << 16 | ((TPID_OFFSET as u32 + 2) << 8) | (TPID_OFFSET as u32 + 3);
459 assert_eq!(frame.tag(), Some(want_tag));
460 assert_eq!(frame.body(), &body[4..]);
463 }
464 }
465
466 #[test]
467 fn test_ethertype() {
468 let mut buf = [0u8; 1014];
470 NetworkEndian::write_u16(&mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..], 1001);
472 assert!(
473 (&mut buf[..])
474 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
475 .is_err()
476 );
477
478 NetworkEndian::write_u16(&mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..], 1000);
480 assert_eq!(
481 (&mut buf[..])
482 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
483 .unwrap()
484 .ethertype(),
485 None
486 );
487
488 let mut buf = [0u8; 1014];
490 NetworkEndian::write_u16(
491 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
492 ETHERNET_MAX_ILLEGAL_ETHERTYPE + 1,
493 );
494 assert_eq!(
495 (&mut buf[..])
496 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
497 .unwrap()
498 .ethertype(),
499 Some(EtherType::Other(ETHERNET_MAX_ILLEGAL_ETHERTYPE + 1))
500 );
501 }
502
503 fn new_test_ethernet_packet_builder() -> EthernetFrameBuilder {
504 EthernetFrameBuilder::new(
505 DEFAULT_SRC_MAC,
506 DEFAULT_DST_MAC,
507 EtherType::Arp,
508 ETHERNET_MIN_BODY_LEN_NO_TAG,
509 )
510 }
511
512 #[test]
513 fn test_serialize() {
514 let buf = new_test_ethernet_packet_builder()
515 .wrap_body((&new_serialize_buf()[..]).into_serializer())
516 .serialize_vec_outer(&mut NoOpSerializationContext)
517 .unwrap();
518 assert_eq!(
519 &buf.as_ref()[..ETHERNET_HDR_LEN_NO_TAG],
520 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x06]
521 );
522 }
523
524 #[test]
525 fn test_serialize_zeroes() {
526 let mut buf_0 = [0; ETHERNET_MIN_FRAME_LEN];
529 let _: Buf<&mut [u8]> = new_test_ethernet_packet_builder()
530 .wrap_body(Buf::new(&mut buf_0[..], ETHERNET_HDR_LEN_NO_TAG..))
531 .serialize_vec_outer(&mut NoOpSerializationContext)
532 .unwrap()
533 .unwrap_a();
534 let mut buf_1 = [0; ETHERNET_MIN_FRAME_LEN];
535 (&mut buf_1[..ETHERNET_HDR_LEN_NO_TAG]).copy_from_slice(&[0xFF; ETHERNET_HDR_LEN_NO_TAG]);
536 let _: Buf<&mut [u8]> = new_test_ethernet_packet_builder()
537 .wrap_body(Buf::new(&mut buf_1[..], ETHERNET_HDR_LEN_NO_TAG..))
538 .serialize_vec_outer(&mut NoOpSerializationContext)
539 .unwrap()
540 .unwrap_a();
541 assert_eq!(&buf_0[..], &buf_1[..]);
542 }
543
544 #[test]
545 fn test_parse_error() {
546 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN - 1];
548 assert!(
549 (&mut buf[..])
550 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
551 .is_err()
552 );
553
554 let mut buf = [0u8; ETHERNET_HDR_LEN_NO_TAG - 1];
557 assert!(
558 (&mut buf[..])
559 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck)
560 .is_err()
561 );
562
563 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
565 NetworkEndian::write_u16(
566 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
567 ETHERNET_MIN_ILLEGAL_ETHERTYPE - 1,
568 );
569 assert!(
570 (&mut buf[..])
571 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
572 .is_err()
573 );
574
575 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
577 NetworkEndian::write_u16(
578 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
579 ETHERNET_MIN_ILLEGAL_ETHERTYPE,
580 );
581 assert!(
582 (&mut buf[..])
583 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
584 .is_err()
585 );
586
587 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
589 NetworkEndian::write_u16(
590 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
591 ETHERNET_MAX_ILLEGAL_ETHERTYPE,
592 );
593 assert!(
594 (&mut buf[..])
595 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
596 .is_err()
597 );
598 }
599
600 #[test]
601 #[should_panic(expected = "bytes is below minimum frame size of")]
602 fn test_serialize_panic() {
603 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN - 1];
605 let mut b = [&mut buf[..]];
606 let buf = b.as_fragmented_byte_slice();
607 let (header, body, footer) = buf.try_split_contiguous(ETHERNET_HDR_LEN_NO_TAG..).unwrap();
608 new_test_ethernet_packet_builder().serialize(
609 &mut NoOpSerializationContext,
610 &mut SerializeTarget { header, footer },
611 body,
612 );
613 }
614
615 #[test]
616 fn test_custom_min_body_len() {
617 const MIN_BODY_LEN: usize = 4;
618 const UNWRITTEN_BYTE: u8 = 0xAA;
619
620 let builder = EthernetFrameBuilder::new(
621 Mac::new([0, 1, 2, 3, 4, 5]),
622 Mac::new([6, 7, 8, 9, 10, 11]),
623 EtherType::Arp,
624 MIN_BODY_LEN,
625 );
626
627 let mut buffer = [UNWRITTEN_BYTE; ETHERNET_MIN_FRAME_LEN];
628 GrowBufferMut::serialize(
631 &mut Buf::new(&mut buffer[..], ETHERNET_HDR_LEN_NO_TAG..ETHERNET_HDR_LEN_NO_TAG),
632 &mut NoOpSerializationContext,
633 builder,
634 );
635
636 let (header, tail) = buffer.split_at(ETHERNET_HDR_LEN_NO_TAG);
637 let (padding, unwritten) = tail.split_at(MIN_BODY_LEN);
638 assert_eq!(
639 header,
640 &[
641 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 08, 06, ]
645 );
646 assert_eq!(padding, &[0; MIN_BODY_LEN]);
647 assert_eq!(
648 unwritten,
649 &[UNWRITTEN_BYTE; ETHERNET_MIN_FRAME_LEN - MIN_BODY_LEN - ETHERNET_HDR_LEN_NO_TAG]
650 );
651 }
652}