xenet_packet/
ethernet.rs

1//! An ethernet packet abstraction.
2
3use crate::PrimitiveValues;
4
5use alloc::vec::Vec;
6use core::fmt;
7
8use xenet_core::mac::MacAddr;
9use xenet_macro::packet;
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14/// Represents the Ethernet header length.
15pub const ETHERNET_HEADER_LEN: usize = 14;
16
17/// Represents the MAC address length.
18pub const MAC_ADDR_LEN: usize = 6;
19
20/// Represents the Ethernet Header.
21#[derive(Clone, Debug, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23pub struct EthernetHeader {
24    /// Destination MAC address
25    pub destination: MacAddr,
26    /// Source MAC address
27    pub source: MacAddr,
28    /// EtherType
29    pub ethertype: EtherType,
30}
31
32impl EthernetHeader {
33    /// Construct an Ethernet header from a byte slice.
34    pub fn from_bytes(packet: &[u8]) -> Result<EthernetHeader, String> {
35        if packet.len() < ETHERNET_HEADER_LEN {
36            return Err("Packet is too small for Ethernet header".to_string());
37        }
38        match EthernetPacket::new(packet) {
39            Some(ethernet_packet) => Ok(EthernetHeader {
40                destination: ethernet_packet.get_destination(),
41                source: ethernet_packet.get_source(),
42                ethertype: ethernet_packet.get_ethertype(),
43            }),
44            None => Err("Failed to parse Ethernet packet".to_string()),
45        }
46    }
47    /// Construct an Ethernet header from a EthernetPacket.
48    pub(crate) fn from_packet(ethernet_packet: &EthernetPacket) -> EthernetHeader {
49        EthernetHeader {
50            destination: ethernet_packet.get_destination(),
51            source: ethernet_packet.get_source(),
52            ethertype: ethernet_packet.get_ethertype(),
53        }
54    }
55}
56
57/// Represents an Ethernet packet.
58#[packet]
59pub struct Ethernet {
60    #[construct_with(u8, u8, u8, u8, u8, u8)]
61    pub destination: MacAddr,
62    #[construct_with(u8, u8, u8, u8, u8, u8)]
63    pub source: MacAddr,
64    #[construct_with(u16)]
65    pub ethertype: EtherType,
66    #[payload]
67    pub payload: Vec<u8>,
68}
69
70#[test]
71fn ethernet_header_test() {
72    let mut packet = [0u8; 14];
73    {
74        let mut ethernet_header = MutableEthernetPacket::new(&mut packet[..]).unwrap();
75
76        let source = MacAddr(0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc);
77        ethernet_header.set_source(source);
78        assert_eq!(ethernet_header.get_source(), source);
79
80        let dest = MacAddr(0xde, 0xf0, 0x12, 0x34, 0x45, 0x67);
81        ethernet_header.set_destination(dest);
82        assert_eq!(ethernet_header.get_destination(), dest);
83
84        ethernet_header.set_ethertype(EtherType::Ipv6);
85        assert_eq!(ethernet_header.get_ethertype(), EtherType::Ipv6);
86    }
87
88    let ref_packet = [
89        0xde, 0xf0, 0x12, 0x34, 0x45, 0x67, /* destination */
90        0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, /* source */
91        0x86, 0xdd, /* ethertype */
92    ];
93    assert_eq!(&ref_packet[..], &packet[..]);
94}
95
96/// Represents the Ethernet types.
97#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
98#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
99pub enum EtherType {
100    Ipv4,
101    Arp,
102    WakeOnLan,
103    Trill,
104    DECnet,
105    Rarp,
106    AppleTalk,
107    Aarp,
108    Ipx,
109    Qnx,
110    Ipv6,
111    FlowControl,
112    CobraNet,
113    Mpls,
114    MplsMcast,
115    PppoeDiscovery,
116    PppoeSession,
117    Vlan,
118    PBridge,
119    Lldp,
120    Ptp,
121    Cfm,
122    QinQ,
123    Rldp,
124    Unknown(u16),
125}
126
127impl EtherType {
128    /// Constructs a new EtherType from u16
129    pub fn new(value: u16) -> EtherType {
130        match value {
131            0x0800 => EtherType::Ipv4,
132            0x0806 => EtherType::Arp,
133            0x0842 => EtherType::WakeOnLan,
134            0x22F3 => EtherType::Trill,
135            0x6003 => EtherType::DECnet,
136            0x8035 => EtherType::Rarp,
137            0x809B => EtherType::AppleTalk,
138            0x80F3 => EtherType::Aarp,
139            0x8137 => EtherType::Ipx,
140            0x8204 => EtherType::Qnx,
141            0x86DD => EtherType::Ipv6,
142            0x8808 => EtherType::FlowControl,
143            0x8819 => EtherType::CobraNet,
144            0x8847 => EtherType::Mpls,
145            0x8848 => EtherType::MplsMcast,
146            0x8863 => EtherType::PppoeDiscovery,
147            0x8864 => EtherType::PppoeSession,
148            0x8100 => EtherType::Vlan,
149            0x88a8 => EtherType::PBridge,
150            0x88cc => EtherType::Lldp,
151            0x88f7 => EtherType::Ptp,
152            0x8902 => EtherType::Cfm,
153            0x9100 => EtherType::QinQ,
154            0x8899 => EtherType::Rldp,
155            _ => EtherType::Unknown(value),
156        }
157    }
158    /// Return the name of the EtherType
159    pub fn name(&self) -> &str {
160        match *self {
161            EtherType::Ipv4 => "IPv4",
162            EtherType::Arp => "ARP",
163            EtherType::WakeOnLan => "WakeOnLan",
164            EtherType::Trill => "Trill",
165            EtherType::DECnet => "DECnet",
166            EtherType::Rarp => "RARP",
167            EtherType::AppleTalk => "AppleTalk",
168            EtherType::Aarp => "AARP",
169            EtherType::Ipx => "IPX",
170            EtherType::Qnx => "QNX",
171            EtherType::Ipv6 => "IPv6",
172            EtherType::FlowControl => "FlowControl",
173            EtherType::CobraNet => "CobraNet",
174            EtherType::Mpls => "MPLS",
175            EtherType::MplsMcast => "MPLS Multicast",
176            EtherType::PppoeDiscovery => "PPPoE Discovery",
177            EtherType::PppoeSession => "PPPoE Session",
178            EtherType::Vlan => "VLAN",
179            EtherType::PBridge => "Provider Bridging",
180            EtherType::Lldp => "LLDP",
181            EtherType::Ptp => "PTP",
182            EtherType::Cfm => "CFM",
183            EtherType::QinQ => "QinQ",
184            EtherType::Rldp => "RLDP",
185            EtherType::Unknown(_) => "Unknown",
186        }
187    }
188}
189
190impl PrimitiveValues for EtherType {
191    type T = (u16,);
192    fn to_primitive_values(&self) -> (u16,) {
193        match *self {
194            EtherType::Ipv4 => (0x0800,),
195            EtherType::Arp => (0x0806,),
196            EtherType::WakeOnLan => (0x0842,),
197            EtherType::Trill => (0x22F3,),
198            EtherType::DECnet => (0x6003,),
199            EtherType::Rarp => (0x8035,),
200            EtherType::AppleTalk => (0x809B,),
201            EtherType::Aarp => (0x80F3,),
202            EtherType::Ipx => (0x8137,),
203            EtherType::Qnx => (0x8204,),
204            EtherType::Ipv6 => (0x86DD,),
205            EtherType::FlowControl => (0x8808,),
206            EtherType::CobraNet => (0x8819,),
207            EtherType::Mpls => (0x8847,),
208            EtherType::MplsMcast => (0x8848,),
209            EtherType::PppoeDiscovery => (0x8863,),
210            EtherType::PppoeSession => (0x8864,),
211            EtherType::Vlan => (0x8100,),
212            EtherType::PBridge => (0x88a8,),
213            EtherType::Lldp => (0x88cc,),
214            EtherType::Ptp => (0x88f7,),
215            EtherType::Cfm => (0x8902,),
216            EtherType::QinQ => (0x9100,),
217            EtherType::Rldp => (0x8899,),
218            EtherType::Unknown(n) => (n,),
219        }
220    }
221}
222
223impl fmt::Display for EtherType {
224    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225        write!(
226            f,
227            "{}",
228            match self {
229                EtherType::Ipv4 => "Ipv4",
230                EtherType::Arp => "Arp",
231                EtherType::WakeOnLan => "WakeOnLan",
232                EtherType::Trill => "Trill",
233                EtherType::DECnet => "DECnet",
234                EtherType::Rarp => "Rarp",
235                EtherType::AppleTalk => "AppleTalk",
236                EtherType::Aarp => "Aarp",
237                EtherType::Ipx => "Ipx",
238                EtherType::Qnx => "Qnx",
239                EtherType::Ipv6 => "Ipv6",
240                EtherType::FlowControl => "FlowControl",
241                EtherType::CobraNet => "CobraNet",
242                EtherType::Mpls => "Mpls",
243                EtherType::MplsMcast => "MplsMcast",
244                EtherType::PppoeDiscovery => "PppoeDiscovery",
245                EtherType::PppoeSession => "PppoeSession",
246                EtherType::Vlan => "Vlan",
247                EtherType::PBridge => "PBridge",
248                EtherType::Lldp => "Lldp",
249                EtherType::Ptp => "Ptp",
250                EtherType::Cfm => "Cfm",
251                EtherType::QinQ => "QinQ",
252                EtherType::Rldp => "Rldp",
253                EtherType::Unknown(_) => "unknown",
254            }
255        )
256    }
257}
258
259#[test]
260fn ether_type_to_str() {
261    use std::format;
262    let ipv4 = EtherType::new(0x0800);
263    assert_eq!(format!("{}", ipv4), "Ipv4");
264    let arp = EtherType::new(0x0806);
265    assert_eq!(format!("{}", arp), "Arp");
266    let unknown = EtherType::new(0x0666);
267    assert_eq!(format!("{}", unknown), "unknown");
268}