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 fn new_test_ethernet_packet_builder() -> EthernetFrameBuilder {
460 EthernetFrameBuilder::new(
461 DEFAULT_SRC_MAC,
462 DEFAULT_DST_MAC,
463 EtherType::Arp,
464 ETHERNET_MIN_BODY_LEN_NO_TAG,
465 )
466 }
467
468 #[test]
469 fn test_serialize() {
470 let buf = new_test_ethernet_packet_builder()
471 .wrap_body((&new_serialize_buf()[..]).into_serializer())
472 .serialize_vec_outer()
473 .unwrap();
474 assert_eq!(
475 &buf.as_ref()[..ETHERNET_HDR_LEN_NO_TAG],
476 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x06]
477 );
478 }
479
480 #[test]
481 fn test_serialize_zeroes() {
482 let mut buf_0 = [0; ETHERNET_MIN_FRAME_LEN];
485 let _: Buf<&mut [u8]> = new_test_ethernet_packet_builder()
486 .wrap_body(Buf::new(&mut buf_0[..], ETHERNET_HDR_LEN_NO_TAG..))
487 .serialize_vec_outer()
488 .unwrap()
489 .unwrap_a();
490 let mut buf_1 = [0; ETHERNET_MIN_FRAME_LEN];
491 (&mut buf_1[..ETHERNET_HDR_LEN_NO_TAG]).copy_from_slice(&[0xFF; ETHERNET_HDR_LEN_NO_TAG]);
492 let _: Buf<&mut [u8]> = new_test_ethernet_packet_builder()
493 .wrap_body(Buf::new(&mut buf_1[..], ETHERNET_HDR_LEN_NO_TAG..))
494 .serialize_vec_outer()
495 .unwrap()
496 .unwrap_a();
497 assert_eq!(&buf_0[..], &buf_1[..]);
498 }
499
500 #[test]
501 fn test_parse_error() {
502 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN - 1];
504 assert!((&mut buf[..])
505 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
506 .is_err());
507
508 let mut buf = [0u8; ETHERNET_HDR_LEN_NO_TAG - 1];
511 assert!((&mut buf[..])
512 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck)
513 .is_err());
514
515 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
517 NetworkEndian::write_u16(
518 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
519 ETHERNET_MIN_ILLEGAL_ETHERTYPE - 1,
520 );
521 assert!((&mut buf[..])
522 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
523 .is_err());
524
525 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
527 NetworkEndian::write_u16(
528 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
529 ETHERNET_MIN_ILLEGAL_ETHERTYPE,
530 );
531 assert!((&mut buf[..])
532 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
533 .is_err());
534
535 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN];
537 NetworkEndian::write_u16(
538 &mut buf[ETHERNET_ETHERTYPE_BYTE_OFFSET..],
539 ETHERNET_MAX_ILLEGAL_ETHERTYPE,
540 );
541 assert!((&mut buf[..])
542 .parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check)
543 .is_err());
544 }
545
546 #[test]
547 #[should_panic(expected = "bytes is below minimum frame size of")]
548 fn test_serialize_panic() {
549 let mut buf = [0u8; ETHERNET_MIN_FRAME_LEN - 1];
551 let mut b = [&mut buf[..]];
552 let buf = b.as_fragmented_byte_slice();
553 let (header, body, footer) = buf.try_split_contiguous(ETHERNET_HDR_LEN_NO_TAG..).unwrap();
554 new_test_ethernet_packet_builder().serialize(&mut SerializeTarget { header, footer }, body);
555 }
556
557 #[test]
558 fn test_custom_min_body_len() {
559 const MIN_BODY_LEN: usize = 4;
560 const UNWRITTEN_BYTE: u8 = 0xAA;
561
562 let builder = EthernetFrameBuilder::new(
563 Mac::new([0, 1, 2, 3, 4, 5]),
564 Mac::new([6, 7, 8, 9, 10, 11]),
565 EtherType::Arp,
566 MIN_BODY_LEN,
567 );
568
569 let mut buffer = [UNWRITTEN_BYTE; ETHERNET_MIN_FRAME_LEN];
570 GrowBufferMut::serialize(
573 &mut Buf::new(&mut buffer[..], ETHERNET_HDR_LEN_NO_TAG..ETHERNET_HDR_LEN_NO_TAG),
574 builder,
575 );
576
577 let (header, tail) = buffer.split_at(ETHERNET_HDR_LEN_NO_TAG);
578 let (padding, unwritten) = tail.split_at(MIN_BODY_LEN);
579 assert_eq!(
580 header,
581 &[
582 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 08, 06, ]
586 );
587 assert_eq!(padding, &[0; MIN_BODY_LEN]);
588 assert_eq!(
589 unwritten,
590 &[UNWRITTEN_BYTE; ETHERNET_MIN_FRAME_LEN - MIN_BODY_LEN - ETHERNET_HDR_LEN_NO_TAG]
591 );
592 }
593}