1use smallvec::SmallVec;
4
5use etherparse::Ethernet2HeaderSlice;
6
7use super::{FieldValue, ParseContext, ParseResult, Protocol};
8use crate::schema::{DataKind, FieldDescriptor};
9
10pub const LINKTYPE_ETHERNET: u16 = 1;
12
13#[allow(dead_code)]
15pub mod ethertype {
16 pub const IPV4: u16 = 0x0800;
18 pub const ARP: u16 = 0x0806;
19 pub const WAKE_ON_LAN: u16 = 0x0842;
20 pub const RARP: u16 = 0x8035;
21 pub const VLAN: u16 = 0x8100;
22 pub const IPV6: u16 = 0x86DD;
23 pub const QINQ: u16 = 0x88A8;
24
25 pub const AVTP: u16 = 0x22F0;
27 pub const SRP: u16 = 0x22EA;
28 pub const TRILL: u16 = 0x22F3;
29
30 pub const DEC_MOP_RC: u16 = 0x6002;
32 pub const DECNET: u16 = 0x6003;
33 pub const DEC_LAT: u16 = 0x6004;
34 pub const APPLETALK: u16 = 0x809B;
35 pub const AARP: u16 = 0x80F3;
36 pub const IPX: u16 = 0x8137;
37 pub const QNX_QNET: u16 = 0x8204;
38
39 pub const SLPP: u16 = 0x8102;
41 pub const VLACP: u16 = 0x8103;
42 pub const FLOW_CONTROL: u16 = 0x8808;
43 pub const LACP: u16 = 0x8809;
44 pub const LLDP: u16 = 0x88CC;
45
46 pub const MPLS: u16 = 0x8847;
48 pub const MPLS_MULTICAST: u16 = 0x8848;
49
50 pub const PPPOE_DISCOVERY: u16 = 0x8863;
52 pub const PPPOE_SESSION: u16 = 0x8864;
53
54 pub const COBRANET: u16 = 0x8819;
56 pub const PROFINET: u16 = 0x8892;
57 pub const HYPERSCSI: u16 = 0x889A;
58 pub const ATA_OVER_ETHERNET: u16 = 0x88A2;
59 pub const ETHERCAT: u16 = 0x88A4;
60 pub const POWERLINK: u16 = 0x88AB;
61 pub const GOOSE: u16 = 0x88B8;
62 pub const GSE: u16 = 0x88B9;
63 pub const SV: u16 = 0x88BA;
64 pub const SERCOS_III: u16 = 0x88CD;
65 pub const MRP: u16 = 0x88E3;
66 pub const PRP: u16 = 0x88FB;
67 pub const HSR: u16 = 0x892F;
68
69 pub const EAP_OVER_LAN: u16 = 0x888E;
71 pub const MACSEC: u16 = 0x88E5;
72
73 pub const PBB: u16 = 0x88E7;
75
76 pub const PTP: u16 = 0x88F7;
78
79 pub const HOMEPLUG_MME: u16 = 0x887B;
81 pub const HOMEPLUG_AV_MME: u16 = 0x88E1;
82 pub const MIKROTIK_ROMON: u16 = 0x88BF;
83 pub const NC_SI: u16 = 0x88F8;
84 pub const CFM_OAM: u16 = 0x8902;
85
86 pub const FCOE: u16 = 0x8906;
88 pub const FCOE_INIT: u16 = 0x8914;
89 pub const ROCE: u16 = 0x8915;
90
91 pub const WSMP: u16 = 0x88DC;
93 pub const TTE: u16 = 0x891D;
94 pub const ECTP: u16 = 0x9000;
95 pub const QINQ_OLD: u16 = 0x9100;
96 pub const VERITAS_LLT: u16 = 0xCAFE;
97}
98
99#[derive(Debug, Clone, Copy)]
101pub struct EthernetProtocol;
102
103impl Protocol for EthernetProtocol {
104 fn name(&self) -> &'static str {
105 "ethernet"
106 }
107
108 fn display_name(&self) -> &'static str {
109 "Ethernet II"
110 }
111
112 fn can_parse(&self, context: &ParseContext) -> Option<u32> {
113 if context.is_root() && context.link_type == LINKTYPE_ETHERNET {
115 return Some(100);
116 }
117
118 if let Some(link_type) = context.hint("link_type") {
121 if link_type == LINKTYPE_ETHERNET as u64 {
122 return Some(100);
123 }
124 }
125
126 None
127 }
128
129 fn parse<'a>(&self, data: &'a [u8], _context: &ParseContext) -> ParseResult<'a> {
130 match Ethernet2HeaderSlice::from_slice(data) {
131 Ok(eth) => {
132 let mut fields = SmallVec::new();
133
134 fields.push(("src_mac", FieldValue::mac(ð.source())));
135 fields.push(("dst_mac", FieldValue::mac(ð.destination())));
136 fields.push(("ethertype", FieldValue::UInt16(eth.ether_type().0)));
137
138 let mut child_hints = SmallVec::new();
139 child_hints.push(("ethertype", eth.ether_type().0 as u64));
140
141 let header_len = eth.slice().len();
142 ParseResult::success(fields, &data[header_len..], child_hints)
143 }
144 Err(e) => ParseResult::error(format!("Ethernet parse error: {e}"), data),
145 }
146 }
147
148 fn schema_fields(&self) -> Vec<FieldDescriptor> {
149 vec![
150 FieldDescriptor::mac_field("eth.src_mac").set_nullable(true),
151 FieldDescriptor::mac_field("eth.dst_mac").set_nullable(true),
152 FieldDescriptor::new("eth.ethertype", DataKind::UInt16).set_nullable(true),
153 ]
154 }
155
156 fn child_protocols(&self) -> &[&'static str] {
157 &["ipv4", "ipv6", "arp", "vlan"]
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_parse_ethernet() {
167 let frame = [
169 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, 0x45, 0x00, ];
174
175 let parser = EthernetProtocol;
176 let context = ParseContext::new(LINKTYPE_ETHERNET);
177 let result = parser.parse(&frame, &context);
178
179 assert!(result.is_ok());
180 assert_eq!(
181 result.get("ethertype"),
182 Some(&FieldValue::UInt16(ethertype::IPV4))
183 );
184 assert_eq!(result.remaining.len(), 2); assert_eq!(result.hint("ethertype"), Some(ethertype::IPV4 as u64));
186 }
187
188 #[test]
189 fn test_parse_ethernet_ipv6() {
190 let frame = [
191 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x86, 0xdd, ];
195
196 let parser = EthernetProtocol;
197 let context = ParseContext::new(LINKTYPE_ETHERNET);
198 let result = parser.parse(&frame, &context);
199
200 assert!(result.is_ok());
201 assert_eq!(
202 result.get("ethertype"),
203 Some(&FieldValue::UInt16(ethertype::IPV6))
204 );
205 assert_eq!(result.hint("ethertype"), Some(ethertype::IPV6 as u64));
206 }
207
208 #[test]
209 fn test_parse_ethernet_arp() {
210 let frame = [
211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x06, 0x00, 0x01, ];
216
217 let parser = EthernetProtocol;
218 let context = ParseContext::new(LINKTYPE_ETHERNET);
219 let result = parser.parse(&frame, &context);
220
221 assert!(result.is_ok());
222 assert_eq!(
223 result.get("ethertype"),
224 Some(&FieldValue::UInt16(ethertype::ARP))
225 );
226 }
227
228 #[test]
229 fn test_can_parse_only_at_root() {
230 let parser = EthernetProtocol;
231
232 let root_ctx = ParseContext::new(LINKTYPE_ETHERNET);
234 assert!(parser.can_parse(&root_ctx).is_some());
235
236 let other_ctx = ParseContext::new(113); assert!(parser.can_parse(&other_ctx).is_none());
239
240 let mut child_ctx = ParseContext::new(LINKTYPE_ETHERNET);
242 child_ctx.parent_protocol = Some("something");
243 assert!(parser.can_parse(&child_ctx).is_none());
244 }
245
246 #[test]
247 fn test_parse_ethernet_too_short() {
248 let short_frame = [0xff, 0xff, 0xff, 0xff, 0xff]; let parser = EthernetProtocol;
251 let context = ParseContext::new(LINKTYPE_ETHERNET);
252 let result = parser.parse(&short_frame, &context);
253
254 assert!(!result.is_ok());
255 assert!(result.error.is_some());
256 }
257
258 #[test]
259 fn test_mac_address_extraction() {
260 let frame = [
261 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x08, 0x00, ];
265
266 let parser = EthernetProtocol;
267 let context = ParseContext::new(LINKTYPE_ETHERNET);
268 let result = parser.parse(&frame, &context);
269
270 assert!(result.is_ok());
271
272 let src_mac = result.get("src_mac").unwrap();
274 let dst_mac = result.get("dst_mac").unwrap();
275
276 assert!(src_mac.as_string().is_some());
277 assert!(dst_mac.as_string().is_some());
278 }
279}