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::{MutablePacket, 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/// Represents a mutable Ethernet packet.
288pub struct MutableEthernetPacket<'a> {
289    buffer: &'a mut [u8],
290}
291
292impl<'a> MutablePacket<'a> for MutableEthernetPacket<'a> {
293    type Packet = EthernetPacket;
294
295    fn new(buffer: &'a mut [u8]) -> Option<Self> {
296        if buffer.len() < ETHERNET_HEADER_LEN {
297            None
298        } else {
299            Some(Self { buffer })
300        }
301    }
302
303    fn packet(&self) -> &[u8] {
304        &*self.buffer
305    }
306
307    fn packet_mut(&mut self) -> &mut [u8] {
308        &mut *self.buffer
309    }
310
311    fn header(&self) -> &[u8] {
312        &self.packet()[..ETHERNET_HEADER_LEN]
313    }
314
315    fn header_mut(&mut self) -> &mut [u8] {
316        let (header, _) = (&mut *self.buffer).split_at_mut(ETHERNET_HEADER_LEN);
317        header
318    }
319
320    fn payload(&self) -> &[u8] {
321        &self.packet()[ETHERNET_HEADER_LEN..]
322    }
323
324    fn payload_mut(&mut self) -> &mut [u8] {
325        let (_, payload) = (&mut *self.buffer).split_at_mut(ETHERNET_HEADER_LEN);
326        payload
327    }
328}
329
330impl<'a> MutableEthernetPacket<'a> {
331    /// Create a mutable packet without performing size checks.
332    pub fn new_unchecked(buffer: &'a mut [u8]) -> Self {
333        Self { buffer }
334    }
335
336    /// Retrieve the destination MAC address.
337    pub fn get_destination(&self) -> MacAddr {
338        MacAddr::from_octets(self.header()[0..MAC_ADDR_LEN].try_into().unwrap())
339    }
340
341    /// Update the destination MAC address.
342    pub fn set_destination(&mut self, addr: MacAddr) {
343        self.header_mut()[0..MAC_ADDR_LEN].copy_from_slice(&addr.octets());
344    }
345
346    /// Retrieve the source MAC address.
347    pub fn get_source(&self) -> MacAddr {
348        MacAddr::from_octets(
349            self.header()[MAC_ADDR_LEN..2 * MAC_ADDR_LEN]
350                .try_into()
351                .unwrap(),
352        )
353    }
354
355    /// Update the source MAC address.
356    pub fn set_source(&mut self, addr: MacAddr) {
357        self.header_mut()[MAC_ADDR_LEN..2 * MAC_ADDR_LEN].copy_from_slice(&addr.octets());
358    }
359
360    /// Retrieve the EtherType.
361    pub fn get_ethertype(&self) -> EtherType {
362        EtherType::new(u16::from_be_bytes([self.header()[12], self.header()[13]]))
363    }
364
365    /// Update the EtherType.
366    pub fn set_ethertype(&mut self, ty: EtherType) {
367        let bytes = ty.value().to_be_bytes();
368        self.header_mut()[12..14].copy_from_slice(&bytes);
369    }
370}
371
372#[cfg(test)]
373mod tests {
374    use super::*;
375    use bytes::Bytes;
376    use nex_core::mac::MacAddr;
377    use std::net::Ipv4Addr;
378
379    #[test]
380    fn test_ethernet_parse_basic() {
381        let raw = [
382            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // dst
383            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // src
384            0x08, 0x00, // EtherType: IPv4
385            0xde, 0xad, 0xbe, 0xef, // Payload (dummy)
386        ];
387        let packet = EthernetPacket::from_bytes(Bytes::copy_from_slice(&raw)).unwrap();
388        assert_eq!(
389            packet.get_destination(),
390            MacAddr::from_octets([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
391        );
392        assert_eq!(
393            packet.get_source(),
394            MacAddr::from_octets([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])
395        );
396        assert_eq!(packet.get_ethertype(), EtherType::Ipv4);
397        assert_eq!(packet.payload.len(), 4);
398    }
399
400    #[test]
401    fn test_ethernet_serialize_roundtrip() {
402        let original = EthernetPacket {
403            header: EthernetHeader {
404                destination: MacAddr::from_octets([1, 2, 3, 4, 5, 6]),
405                source: MacAddr::from_octets([10, 20, 30, 40, 50, 60]),
406                ethertype: EtherType::Arp,
407            },
408            payload: Bytes::from_static(&[0xde, 0xad, 0xbe, 0xef]),
409        };
410
411        let bytes = original.to_bytes();
412        let parsed = EthernetPacket::from_bytes(bytes).unwrap();
413
414        assert_eq!(parsed, original);
415    }
416
417    #[test]
418    fn test_ethernet_header_parse_and_serialize() {
419        let header = EthernetHeader {
420            destination: MacAddr::from_octets([1, 1, 1, 1, 1, 1]),
421            source: MacAddr::from_octets([2, 2, 2, 2, 2, 2]),
422            ethertype: EtherType::Ipv6,
423        };
424        let bytes = header.to_bytes();
425        let parsed = EthernetHeader::from_bytes(bytes.clone()).unwrap();
426
427        assert_eq!(header, parsed);
428        assert_eq!(bytes.len(), ETHERNET_HEADER_LEN);
429    }
430
431    #[test]
432    fn test_ethernet_parse_too_short() {
433        let short = Bytes::from_static(&[0, 1, 2, 3]); // insufficient length
434        assert!(EthernetPacket::from_bytes(short).is_none());
435    }
436
437    #[test]
438    fn test_ethernet_unknown_ethertype() {
439        let raw = [
440            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xde,
441            0xad, // Unknown EtherType
442            0x00, 0x11, 0x22, 0x33,
443        ];
444        let packet = EthernetPacket::from_bytes(Bytes::copy_from_slice(&raw)).unwrap();
445        match packet.get_ethertype() {
446            EtherType::Unknown(val) => assert_eq!(val, 0xdead),
447            _ => panic!("Expected unknown EtherType"),
448        }
449    }
450
451    #[test]
452    fn test_mutable_chaining_updates_in_place() {
453        let mut raw = [
454            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // dst
455            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // src
456            0x08, 0x00, // IPv4 EtherType
457            0x45, 0x00, 0x00, 0x1c, // IPv4 header start (20 bytes header + 8 bytes payload)
458            0x1c, 0x46, 0x40, 0x00, 0x40, 0x11, 0x00, 0x00, // rest of IPv4 header
459            0xc0, 0xa8, 0x00, 0x01, // src IP
460            0xc0, 0xa8, 0x00, 0xc7, // dst IP
461            0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe, // payload
462        ];
463
464        let mut ethernet = MutableEthernetPacket::new(&mut raw).expect("mutable ethernet");
465        assert_eq!(ethernet.get_ethertype(), EtherType::Ipv4);
466
467        use crate::ipv4::MutableIpv4Packet;
468
469        {
470            let mut ipv4 = MutableIpv4Packet::new(ethernet.payload_mut()).expect("mutable ipv4");
471            ipv4.set_ttl(99);
472            ipv4.set_source(Ipv4Addr::new(10, 0, 0, 1));
473            ipv4.payload_mut()[0] = 0xaa;
474        }
475
476        {
477            let packet_view = ethernet.packet();
478            assert_eq!(packet_view[22], 99);
479            assert_eq!(&packet_view[26..30], &[10, 0, 0, 1]);
480            assert_eq!(packet_view[34], 0xaa);
481        }
482
483        drop(ethernet);
484        assert_eq!(raw[22], 99);
485        assert_eq!(&raw[26..30], &[10, 0, 0, 1]);
486        assert_eq!(raw[34], 0xaa);
487    }
488}