nex_packet/
ethernet.rs

1//! An ethernet packet abstraction.
2
3use bytes::Bytes;
4use core::fmt;
5use nex_core::mac::MacAddr;
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::packet::Packet;
11
12/// Represents the Ethernet header length.
13pub const ETHERNET_HEADER_LEN: usize = 14;
14
15/// Represents the MAC address length.
16pub const MAC_ADDR_LEN: usize = 6;
17
18/// Represents the Ethernet types.
19#[repr(u16)]
20#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22pub enum EtherType {
23    Ipv4,
24    Arp,
25    WakeOnLan,
26    Trill,
27    DECnet,
28    Rarp,
29    AppleTalk,
30    Aarp,
31    Ipx,
32    Qnx,
33    Ipv6,
34    FlowControl,
35    CobraNet,
36    Mpls,
37    MplsMcast,
38    PppoeDiscovery,
39    PppoeSession,
40    Vlan,
41    PBridge,
42    Lldp,
43    Ptp,
44    Cfm,
45    QinQ,
46    Rldp,
47    Unknown(u16),
48}
49
50impl EtherType {
51    /// Constructs a new EtherType from u16
52    pub fn new(value: u16) -> EtherType {
53        match value {
54            0x0800 => EtherType::Ipv4,
55            0x0806 => EtherType::Arp,
56            0x0842 => EtherType::WakeOnLan,
57            0x22F3 => EtherType::Trill,
58            0x6003 => EtherType::DECnet,
59            0x8035 => EtherType::Rarp,
60            0x809B => EtherType::AppleTalk,
61            0x80F3 => EtherType::Aarp,
62            0x8137 => EtherType::Ipx,
63            0x8204 => EtherType::Qnx,
64            0x86DD => EtherType::Ipv6,
65            0x8808 => EtherType::FlowControl,
66            0x8819 => EtherType::CobraNet,
67            0x8847 => EtherType::Mpls,
68            0x8848 => EtherType::MplsMcast,
69            0x8863 => EtherType::PppoeDiscovery,
70            0x8864 => EtherType::PppoeSession,
71            0x8100 => EtherType::Vlan,
72            0x88a8 => EtherType::PBridge,
73            0x88cc => EtherType::Lldp,
74            0x88f7 => EtherType::Ptp,
75            0x8902 => EtherType::Cfm,
76            0x9100 => EtherType::QinQ,
77            0x8899 => EtherType::Rldp,
78            _ => EtherType::Unknown(value),
79        }
80    }
81    /// Return the name of the EtherType
82    pub fn name(&self) -> &str {
83        match *self {
84            EtherType::Ipv4 => "IPv4",
85            EtherType::Arp => "ARP",
86            EtherType::WakeOnLan => "WakeOnLan",
87            EtherType::Trill => "Trill",
88            EtherType::DECnet => "DECnet",
89            EtherType::Rarp => "RARP",
90            EtherType::AppleTalk => "AppleTalk",
91            EtherType::Aarp => "AARP",
92            EtherType::Ipx => "IPX",
93            EtherType::Qnx => "QNX",
94            EtherType::Ipv6 => "IPv6",
95            EtherType::FlowControl => "FlowControl",
96            EtherType::CobraNet => "CobraNet",
97            EtherType::Mpls => "MPLS",
98            EtherType::MplsMcast => "MPLS Multicast",
99            EtherType::PppoeDiscovery => "PPPoE Discovery",
100            EtherType::PppoeSession => "PPPoE Session",
101            EtherType::Vlan => "VLAN",
102            EtherType::PBridge => "Provider Bridging",
103            EtherType::Lldp => "LLDP",
104            EtherType::Ptp => "PTP",
105            EtherType::Cfm => "CFM",
106            EtherType::QinQ => "QinQ",
107            EtherType::Rldp => "RLDP",
108            EtherType::Unknown(_) => "Unknown",
109        }
110    }
111    pub fn value(&self) -> u16 {
112        match *self {
113            EtherType::Ipv4 => 0x0800,
114            EtherType::Arp => 0x0806,
115            EtherType::WakeOnLan => 0x0842,
116            EtherType::Trill => 0x22F3,
117            EtherType::DECnet => 0x6003,
118            EtherType::Rarp => 0x8035,
119            EtherType::AppleTalk => 0x809B,
120            EtherType::Aarp => 0x80F3,
121            EtherType::Ipx => 0x8137,
122            EtherType::Qnx => 0x8204,
123            EtherType::Ipv6 => 0x86DD,
124            EtherType::FlowControl => 0x8808,
125            EtherType::CobraNet => 0x8819,
126            EtherType::Mpls => 0x8847,
127            EtherType::MplsMcast => 0x8848,
128            EtherType::PppoeDiscovery => 0x8863,
129            EtherType::PppoeSession => 0x8864,
130            EtherType::Vlan => 0x8100,
131            EtherType::PBridge => 0x88a8,
132            EtherType::Lldp => 0x88cc,
133            EtherType::Ptp => 0x88f7,
134            EtherType::Cfm => 0x8902,
135            EtherType::QinQ => 0x9100,
136            EtherType::Rldp => 0x8899,
137            EtherType::Unknown(value) => value,
138        }
139    }
140}
141
142impl fmt::Display for EtherType {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        write!(f, "{}", self.name())
145    }
146}
147
148/// Represents the Ethernet Header.
149#[derive(Clone, Debug, PartialEq, Eq)]
150#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
151pub struct EthernetHeader {
152    /// Destination MAC address
153    pub destination: MacAddr,
154    /// Source MAC address
155    pub source: MacAddr,
156    /// EtherType
157    pub ethertype: EtherType,
158}
159
160impl EthernetHeader {
161    /// Construct an Ethernet header from a byte slice.
162    pub fn from_bytes(packet: Bytes) -> Result<EthernetHeader, String> {
163        if packet.len() < ETHERNET_HEADER_LEN {
164            return Err("Packet is too small for Ethernet header".to_string());
165        }
166        match EthernetPacket::from_bytes(packet) {
167            Some(ethernet_packet) => Ok(EthernetHeader {
168                destination: ethernet_packet.get_destination(),
169                source: ethernet_packet.get_source(),
170                ethertype: ethernet_packet.get_ethertype(),
171            }),
172            None => Err("Failed to parse Ethernet packet".to_string()),
173        }
174    }
175    pub fn to_bytes(&self) -> Bytes {
176        let mut buf = Vec::with_capacity(ETHERNET_HEADER_LEN);
177        buf.extend_from_slice(&self.destination.octets());
178        buf.extend_from_slice(&self.source.octets());
179        buf.extend_from_slice(&self.ethertype.value().to_be_bytes());
180        Bytes::from(buf)
181    }
182}
183
184/// Represents an Ethernet packet.
185#[derive(Clone, Debug, PartialEq, Eq)]
186#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
187pub struct EthernetPacket {
188    /// The Ethernet header.
189    pub header: EthernetHeader,
190    pub payload: Bytes,
191}
192
193impl Packet for EthernetPacket {
194    type Header = EthernetHeader;
195
196    fn from_buf(bytes: &[u8]) -> Option<Self> {
197        if bytes.len() < ETHERNET_HEADER_LEN {
198            return None;
199        }
200        let destination = MacAddr::from_octets(bytes[0..MAC_ADDR_LEN].try_into().unwrap());
201        let source =
202            MacAddr::from_octets(bytes[MAC_ADDR_LEN..2 * MAC_ADDR_LEN].try_into().unwrap());
203        let ethertype = EtherType::new(u16::from_be_bytes([bytes[12], bytes[13]]));
204        let payload = Bytes::copy_from_slice(&bytes[ETHERNET_HEADER_LEN..]);
205
206        Some(EthernetPacket {
207            header: EthernetHeader {
208                destination,
209                source,
210                ethertype,
211            },
212            payload,
213        })
214    }
215    fn from_bytes(bytes: Bytes) -> Option<Self> {
216        Self::from_buf(&bytes)
217    }
218    fn to_bytes(&self) -> Bytes {
219        let mut buf = Vec::with_capacity(ETHERNET_HEADER_LEN + self.payload.len());
220        buf.extend_from_slice(&self.header.to_bytes());
221        buf.extend_from_slice(&self.payload);
222        Bytes::from(buf)
223    }
224    fn header(&self) -> Bytes {
225        self.header.to_bytes()
226    }
227    fn payload(&self) -> Bytes {
228        self.payload.clone()
229    }
230    fn header_len(&self) -> usize {
231        ETHERNET_HEADER_LEN
232    }
233    fn payload_len(&self) -> usize {
234        self.payload.len()
235    }
236
237    fn total_len(&self) -> usize {
238        self.header_len() + self.payload_len()
239    }
240
241    fn into_parts(self) -> (Self::Header, Bytes) {
242        (self.header, self.payload)
243    }
244}
245
246impl EthernetPacket {
247    /// Create a new Ethernet packet.
248    pub fn new(header: EthernetHeader, payload: Bytes) -> Self {
249        EthernetPacket { header, payload }
250    }
251    /// Get the destination MAC address.
252    pub fn get_destination(&self) -> MacAddr {
253        self.header.destination
254    }
255
256    /// Get the source MAC address.
257    pub fn get_source(&self) -> MacAddr {
258        self.header.source
259    }
260
261    /// Get the EtherType.
262    pub fn get_ethertype(&self) -> EtherType {
263        self.header.ethertype
264    }
265
266    pub fn ip_packet(&self) -> Option<Bytes> {
267        if self.get_ethertype() == EtherType::Ipv4 || self.get_ethertype() == EtherType::Ipv6 {
268            Some(self.payload.clone())
269        } else {
270            None
271        }
272    }
273}
274
275impl fmt::Display for EthernetPacket {
276    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277        write!(
278            f,
279            "EthernetPacket {{ destination: {}, source: {}, ethertype: {} }}",
280            self.get_destination(),
281            self.get_source(),
282            self.get_ethertype()
283        )
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290    use bytes::Bytes;
291    use nex_core::mac::MacAddr;
292
293    #[test]
294    fn test_ethernet_parse_basic() {
295        let raw = [
296            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // dst
297            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // src
298            0x08, 0x00, // EtherType: IPv4
299            0xde, 0xad, 0xbe, 0xef, // Payload (dummy)
300        ];
301        let packet = EthernetPacket::from_bytes(Bytes::copy_from_slice(&raw)).unwrap();
302        assert_eq!(
303            packet.get_destination(),
304            MacAddr::from_octets([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
305        );
306        assert_eq!(
307            packet.get_source(),
308            MacAddr::from_octets([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])
309        );
310        assert_eq!(packet.get_ethertype(), EtherType::Ipv4);
311        assert_eq!(packet.payload.len(), 4);
312    }
313
314    #[test]
315    fn test_ethernet_serialize_roundtrip() {
316        let original = EthernetPacket {
317            header: EthernetHeader {
318                destination: MacAddr::from_octets([1, 2, 3, 4, 5, 6]),
319                source: MacAddr::from_octets([10, 20, 30, 40, 50, 60]),
320                ethertype: EtherType::Arp,
321            },
322            payload: Bytes::from_static(&[0xde, 0xad, 0xbe, 0xef]),
323        };
324
325        let bytes = original.to_bytes();
326        let parsed = EthernetPacket::from_bytes(bytes).unwrap();
327
328        assert_eq!(parsed, original);
329    }
330
331    #[test]
332    fn test_ethernet_header_parse_and_serialize() {
333        let header = EthernetHeader {
334            destination: MacAddr::from_octets([1, 1, 1, 1, 1, 1]),
335            source: MacAddr::from_octets([2, 2, 2, 2, 2, 2]),
336            ethertype: EtherType::Ipv6,
337        };
338        let bytes = header.to_bytes();
339        let parsed = EthernetHeader::from_bytes(bytes.clone()).unwrap();
340
341        assert_eq!(header, parsed);
342        assert_eq!(bytes.len(), ETHERNET_HEADER_LEN);
343    }
344
345    #[test]
346    fn test_ethernet_parse_too_short() {
347        let short = Bytes::from_static(&[0, 1, 2, 3]); // insufficient length
348        assert!(EthernetPacket::from_bytes(short).is_none());
349    }
350
351    #[test]
352    fn test_ethernet_unknown_ethertype() {
353        let raw = [
354            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xde,
355            0xad, // Unknown EtherType
356            0x00, 0x11, 0x22, 0x33,
357        ];
358        let packet = EthernetPacket::from_bytes(Bytes::copy_from_slice(&raw)).unwrap();
359        match packet.get_ethertype() {
360            EtherType::Unknown(val) => assert_eq!(val, 0xdead),
361            _ => panic!("Expected unknown EtherType"),
362        }
363    }
364}