use crate::protocol::codec::Decode; use nom::number; use nom::IResult; /****************************************************************************** * Struct ******************************************************************************/ #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct MacAddress(pub [u8; 6]); #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum EtherType { LANMIN, // 802.3 Min data length LANMAX, // 802.3 Max data length IPv4, // Internet Protocol version 4 (IPv4) [RFC7042] ARP, // Address Resolution Protocol (ARP) [RFC7042] WOL, // Wake on LAN TRILL, // IETF TRILL Protocol [IEEE] DECnet, // DECnet Phase IV RARP, // Reverse Address Resolution Protocol (RARP) [RFC903] AppleTalk, // AppleTalk - EtherTalk [Apple] AARP, // AppleTalk Address Resolution Protocol (AARP) [Apple] VLAN, // VLAN-tagged frame (IEEE 802.1Q) and Shortest Path Bridging IEEE 802.1aq[5] IPX, // IPX [Xerox] Qnet, // QNX Qnet [QNX Software Systems] IPv6, // Internet Protocol Version 6 (IPv6) [RFC7042] FlowControl, // Ethernet Flow Control [IEEE 802.3x] CobraNet, // CobraNet [CobraNet] MPLSuni, // MPLS Unicast [RFC 3032] MPLSmulti, // MPLS Multicast [RFC 5332] PPPoEdiscovery, // PPPOE Discovery Stage [RFC 2516] PPPoEsession, // PPPoE Session Stage [RFC 2516] HomePlug, // HomePlug 1.0 MME EAPOL, // EAP over LAN (IEEE 802.1X) PROFINET, // PROFINET Protocol HyperSCSI, // HyperSCSI (SCSI over Ethernet) ATAOE, // ATA over Ethernet EtherCAT, // EtherCAT Protocol QinQ, // Provider Bridging (IEEE 802.1ad) & Shortest Path Bridging IEEE 802.1aq[5] Powerlink, // Ethernet Powerlink[citation needed] GOOSE, // GOOSE (Generic Object Oriented Substation event) GSE, // GSE (Generic Substation Events) Management Services LLDP, // Link Layer Discovery Protocol (LLDP) [IEEE 802.1AB] SERCOS, // SERCOS III HomePlugAV, // HomePlug AV MME[citation needed] MRP, // Media Redundancy Protocol (IEC62439-2) MACsec, // MAC security (IEEE 802.1AE) PBB, // Provider Backbone Bridges (PBB) (IEEE 802.1ah) PTP, // Precision Time Protocol (PTP) over Ethernet [IEEE 1588] PRP, // Parallel Redundancy Protocol (PRP) CFM, // IEEE 802.1ag Connectivity Fault Management (CFM) Protocol / ITU-T Recommendation Y.1731 (OAM) FCoE, // Fibre Channel over Ethernet (FCoE) FCoEi, // FCoE Initialization Protocol RoCE, // RDMA over Converged Ethernet (RoCE) TTE, // TTEthernet Protocol Control Frame (TTE) HSR, // High-availability Seamless Redundancy (HSR) CTP, // Ethernet Configuration Testing Protocol[6] VLANdouble, // VLAN-tagged (IEEE 802.1Q) frame with double tagging Other(u16), } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct EthernetFrame { pub source_mac: MacAddress, pub dest_mac: MacAddress, pub ether_type: EtherType, } /****************************************************************************** * API ******************************************************************************/ impl From for EtherType { fn from(raw: u16) -> Self { match raw { 0x002E => Self::LANMIN, 0x05DC => Self::LANMAX, 0x0800 => Self::IPv4, 0x0806 => Self::ARP, 0x0842 => Self::WOL, 0x22F3 => Self::TRILL, 0x6003 => Self::DECnet, 0x8035 => Self::RARP, 0x809B => Self::AppleTalk, 0x80F3 => Self::AARP, 0x8100 => Self::VLAN, 0x8137 => Self::IPX, 0x8204 => Self::Qnet, 0x86DD => Self::IPv6, 0x8808 => Self::FlowControl, 0x8819 => Self::CobraNet, 0x8847 => Self::MPLSuni, 0x8848 => Self::MPLSmulti, 0x8863 => Self::PPPoEdiscovery, 0x8864 => Self::PPPoEsession, 0x887B => Self::HomePlug, 0x888E => Self::EAPOL, 0x8892 => Self::PROFINET, 0x889A => Self::HyperSCSI, 0x88A2 => Self::ATAOE, 0x88A4 => Self::EtherCAT, 0x88A8 => Self::QinQ, 0x88AB => Self::Powerlink, 0x88B8 => Self::GOOSE, 0x88B9 => Self::GSE, 0x88CC => Self::LLDP, 0x88CD => Self::SERCOS, 0x88E1 => Self::HomePlugAV, 0x88E3 => Self::MRP, 0x88E5 => Self::MACsec, 0x88E7 => Self::PBB, 0x88F7 => Self::PTP, 0x88FB => Self::PRP, 0x8902 => Self::CFM, 0x8906 => Self::FCoE, 0x8914 => Self::FCoEi, 0x8915 => Self::RoCE, 0x891D => Self::TTE, 0x892F => Self::HSR, 0x9000 => Self::CTP, 0x9100 => Self::VLANdouble, other => Self::Other(other), } } } impl EtherType { fn decode(input: &[u8]) -> IResult<&[u8], EtherType> { let (input, ether_type) = number::streaming::be_u16(input)?; Ok((input, ether_type.into())) } } impl MacAddress { fn decode(input: &[u8]) -> IResult<&[u8], MacAddress> { let (input, mac_address) = nom::bytes::streaming::take(6u8)(input)?; Ok((input, MacAddress(<[u8; 6]>::try_from(mac_address).unwrap()))) } } impl Decode for EthernetFrame { fn decode(input: &[u8]) -> IResult<&[u8], EthernetFrame> { let (input, dest_mac) = MacAddress::decode(input)?; let (input, source_mac) = MacAddress::decode(input)?; let (input, ether_type) = EtherType::decode(input)?; Ok(( input, EthernetFrame { source_mac, dest_mac, ether_type, }, )) } } /****************************************************************************** * TEST ******************************************************************************/ #[cfg(test)] mod tests { use super::{EtherType, EthernetFrame, MacAddress}; use crate::protocol::codec::Decode; const LAST_SLICE: &'static [u8] = &[0xff]; #[test] fn ethernet_frame_decode() { /* * Ethernet II, Src: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea), Dst: Charge-A_08:02:be (4c:bc:98:08:02:be) * Destination: Charge-A_08:02:be (4c:bc:98:08:02:be) * Address: Charge-A_08:02:be (4c:bc:98:08:02:be) * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default) * .... ...0 .... .... .... .... = IG bit: Individual address (unicast) * Source: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea) * Address: Apple_0a:c5:ea (3c:a6:f6:0a:c5:ea) * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default) * .... ...0 .... .... .... .... = IG bit: Individual address (unicast) * Type: IPv4 (0x0800) */ let bytes = [ 0x4c, 0xbc, 0x98, 0x08, 0x02, 0xbe, /* Destination Address */ 0x3c, 0xa6, 0xf6, 0x0a, 0xc5, 0xea, /* Source Address */ 0x08, 0x00, /* Type */ 0xff, /* Payload */ ]; let expectation = EthernetFrame { source_mac: MacAddress([0x3c, 0xa6, 0xf6, 0x0a, 0xc5, 0xea]), dest_mac: MacAddress([0x4c, 0xbc, 0x98, 0x08, 0x02, 0xbe]), ether_type: EtherType::IPv4, }; assert_eq!(EthernetFrame::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let ethernet = EthernetFrame::decode(&bytes); if let Ok((payload, header)) = ethernet { println!("return: {:?}, payload: {}", header, payload.len()); } else { println!("return: Incomplete data"); } } }