retina_core/protocols/packet/
ethernet.rs1use crate::memory::mbuf::Mbuf;
4use crate::protocols::packet::{Packet, PacketHeader, PacketParseError};
5use crate::utils::types::*;
6
7use anyhow::{bail, Result};
8use pnet::datalink::MacAddr;
9
10const VLAN_802_1Q: u16 = 0x8100;
11const VLAN_802_1AD: u16 = 0x88a8;
12
13const TAG_SIZE: usize = 4;
14const HDR_SIZE: usize = 14;
15const HDR_SIZE_802_1Q: usize = HDR_SIZE + TAG_SIZE;
16const HDR_SIZE_802_1AD: usize = HDR_SIZE_802_1Q + TAG_SIZE;
17
18#[derive(Debug)]
23pub struct Ethernet<'a> {
24 header: EthernetHeader,
26 offset: usize,
28 mbuf: &'a Mbuf,
30}
31
32impl<'a> Ethernet<'a> {
33 #[inline]
35 pub fn dst(&self) -> MacAddr {
36 self.header.dst
37 }
38
39 #[inline]
41 pub fn src(&self) -> MacAddr {
42 self.header.src
43 }
44
45 #[inline]
48 pub fn ether_type(&self) -> u16 {
49 self.next_header().unwrap_or(0) as u16
50 }
51}
52
53impl<'a> Packet<'a> for Ethernet<'a> {
54 fn mbuf(&self) -> &Mbuf {
55 self.mbuf
56 }
57
58 fn header_len(&self) -> usize {
59 self.header.length()
60 }
61
62 fn next_header_offset(&self) -> usize {
63 self.offset + self.header_len()
64 }
65
66 fn next_header(&self) -> Option<usize> {
67 let ether_type: u16 = u16::from(self.header.ether_type);
68 match ether_type {
69 VLAN_802_1Q => {
70 if let Ok(dot1q) = self.mbuf.get_data(HDR_SIZE) {
71 let dot1q: Dot1q = unsafe { *dot1q };
72 Some(u16::from(dot1q.ether_type).into())
73 } else {
74 None
75 }
76 }
77 VLAN_802_1AD => {
78 None
80 }
81 _ => Some(ether_type.into()),
82 }
83 }
84
85 fn parse_from(outer: &'a impl Packet<'a>) -> Result<Self>
86 where
87 Self: Sized,
88 {
89 if let Ok(header) = outer.mbuf().get_data(0) {
90 Ok(Ethernet {
91 header: unsafe { *header },
92 offset: 0,
93 mbuf: outer.mbuf(),
94 })
95 } else {
96 bail!(PacketParseError::InvalidRead)
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy)]
103#[repr(C, packed)]
104struct EthernetHeader {
105 dst: MacAddr,
106 src: MacAddr,
107 ether_type: u16be,
108}
109
110impl PacketHeader for EthernetHeader {
111 fn length(&self) -> usize {
112 match self.ether_type.into() {
113 VLAN_802_1Q => HDR_SIZE_802_1Q,
114 VLAN_802_1AD => HDR_SIZE_802_1AD,
115 _ => HDR_SIZE,
116 }
117 }
118}
119
120#[derive(Debug, Clone, Copy)]
126#[repr(C, packed)]
127struct Dot1q {
128 tci: u16be,
129 ether_type: u16be,
130}
131
132impl PacketHeader for Dot1q {
133 fn length(&self) -> usize {
136 TAG_SIZE
137 }
138}
139
140