Skip to main content

net_wire/ethernet/
frame.rs

1use crate::error::ParseError;
2
3use super::address::MacAddress;
4use super::ether_type::EtherType;
5
6pub(super) const HEADER_LENGTH: usize = 14;
7const DESTINATION: core::ops::Range<usize> = 0..6;
8const SOURCE: core::ops::Range<usize> = 6..12;
9const ETHER_TYPE: core::ops::Range<usize> = 12..14;
10
11/// A validated immutable borrow of one Ethernet II frame.
12///
13/// The fixed destination, source, and protocol-type header order follows
14/// [RFC 894](https://www.rfc-editor.org/rfc/rfc894). Callers must remove any frame check
15/// sequence (FCS) before parsing because every supplied byte after the fixed header is
16/// payload.
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub struct EthernetFrame<'a> {
19    bytes: &'a [u8],
20}
21
22impl<'a> EthernetFrame<'a> {
23    /// Validates and borrows an Ethernet II frame.
24    ///
25    /// The parser rejects inputs shorter than the 14-octet destination/source/type
26    /// header described by [RFC 894](https://www.rfc-editor.org/rfc/rfc894). Every
27    /// remaining supplied octet is exposed unchanged as payload; callers must remove any
28    /// frame check sequence (FCS) before parsing. No minimum payload length is imposed by
29    /// this wire view.
30    pub fn parse(bytes: &'a [u8]) -> Result<Self, ParseError> {
31        validate_frame_length(bytes.len())?;
32        Ok(Self { bytes })
33    }
34
35    /// Returns the destination Ethernet address.
36    ///
37    /// RFC 894 places the destination address in the first six octets of the Ethernet
38    /// header: <https://www.rfc-editor.org/rfc/rfc894>.
39    #[inline]
40    pub fn destination(&self) -> MacAddress {
41        MacAddress::new(
42            self.bytes[DESTINATION]
43                .try_into()
44                .expect("validated header"),
45        )
46    }
47
48    /// Returns the source Ethernet address.
49    ///
50    /// RFC 894 places the source address immediately after the destination address:
51    /// <https://www.rfc-editor.org/rfc/rfc894>.
52    #[inline]
53    pub fn source(&self) -> MacAddress {
54        MacAddress::new(self.bytes[SOURCE].try_into().expect("validated header"))
55    }
56
57    /// Returns the Ethernet protocol type.
58    ///
59    /// RFC 894 places the two-octet protocol type after the source address and transmits
60    /// it most-significant octet first: <https://www.rfc-editor.org/rfc/rfc894>.
61    #[inline]
62    pub fn ether_type(&self) -> EtherType {
63        EtherType::new(u16::from_be_bytes(
64            self.bytes[ETHER_TYPE].try_into().expect("validated header"),
65        ))
66    }
67
68    /// Returns the payload bytes following the fixed Ethernet II header.
69    ///
70    /// This is the data field after the type field in the RFC 894 Ethernet encapsulation:
71    /// <https://www.rfc-editor.org/rfc/rfc894>. The returned slice borrows the input.
72    #[inline]
73    pub fn payload(&self) -> &'a [u8] {
74        &self.bytes[HEADER_LENGTH..]
75    }
76
77    /// Returns all represented frame bytes.
78    ///
79    /// The byte layout is the destination/source/type/payload order described by
80    /// [RFC 894](https://www.rfc-editor.org/rfc/rfc894). Callers must remove any frame
81    /// check sequence (FCS) before parsing; it cannot be distinguished from payload here.
82    #[inline]
83    pub fn as_bytes(&self) -> &'a [u8] {
84        self.bytes
85    }
86}
87
88/// A validated mutable borrow of one Ethernet II frame.
89///
90/// Its fixed header uses the destination, source, and protocol-type order described by
91/// [RFC 894](https://www.rfc-editor.org/rfc/rfc894). Callers must remove any frame check
92/// sequence (FCS) before parsing because every supplied byte after the fixed header is
93/// payload.
94#[derive(Debug, Eq, PartialEq)]
95pub struct EthernetFrameMut<'a> {
96    bytes: &'a mut [u8],
97}
98
99impl<'a> EthernetFrameMut<'a> {
100    pub(super) fn from_validated(bytes: &'a mut [u8]) -> Self {
101        Self { bytes }
102    }
103
104    /// Validates and mutably borrows an Ethernet II frame.
105    ///
106    /// The parser rejects inputs shorter than the 14-octet destination/source/type
107    /// header described by [RFC 894](https://www.rfc-editor.org/rfc/rfc894). Every
108    /// remaining supplied octet is payload and remains available for independent protocol
109    /// parsing; callers must remove any frame check sequence (FCS) before parsing.
110    pub fn parse(bytes: &'a mut [u8]) -> Result<Self, ParseError> {
111        validate_frame_length(bytes.len())?;
112        Ok(Self { bytes })
113    }
114
115    /// Returns the destination Ethernet address.
116    ///
117    /// RFC 894 assigns the first six header octets to the destination address:
118    /// <https://www.rfc-editor.org/rfc/rfc894>.
119    #[inline]
120    pub fn destination(&self) -> MacAddress {
121        MacAddress::new(
122            self.bytes[DESTINATION]
123                .try_into()
124                .expect("validated header"),
125        )
126    }
127
128    /// Returns the source Ethernet address.
129    ///
130    /// RFC 894 assigns the next six header octets to the source address:
131    /// <https://www.rfc-editor.org/rfc/rfc894>.
132    #[inline]
133    pub fn source(&self) -> MacAddress {
134        MacAddress::new(self.bytes[SOURCE].try_into().expect("validated header"))
135    }
136
137    /// Returns the Ethernet protocol type.
138    ///
139    /// RFC 894 places this two-octet, most-significant-octet-first field after the source
140    /// address: <https://www.rfc-editor.org/rfc/rfc894>.
141    #[inline]
142    pub fn ether_type(&self) -> EtherType {
143        EtherType::new(u16::from_be_bytes(
144            self.bytes[ETHER_TYPE].try_into().expect("validated header"),
145        ))
146    }
147
148    /// Replaces the destination Ethernet address.
149    ///
150    /// This writes the first six header octets assigned to the destination address by
151    /// [RFC 894](https://www.rfc-editor.org/rfc/rfc894).
152    #[inline]
153    pub fn set_destination(&mut self, address: MacAddress) {
154        self.bytes[DESTINATION].copy_from_slice(&address.octets());
155    }
156
157    /// Replaces the source Ethernet address.
158    ///
159    /// This writes the six header octets assigned to the source address by
160    /// [RFC 894](https://www.rfc-editor.org/rfc/rfc894).
161    #[inline]
162    pub fn set_source(&mut self, address: MacAddress) {
163        self.bytes[SOURCE].copy_from_slice(&address.octets());
164    }
165
166    /// Replaces the Ethernet protocol type.
167    ///
168    /// This writes the most-significant-octet-first type field specified by
169    /// [RFC 894](https://www.rfc-editor.org/rfc/rfc894).
170    #[inline]
171    pub fn set_ether_type(&mut self, ether_type: EtherType) {
172        self.bytes[ETHER_TYPE].copy_from_slice(&ether_type.raw().to_be_bytes());
173    }
174
175    /// Returns the payload bytes following the fixed Ethernet II header.
176    ///
177    /// This borrows the data field after the type field in RFC 894's encapsulation:
178    /// <https://www.rfc-editor.org/rfc/rfc894>.
179    #[inline]
180    pub fn payload(&self) -> &[u8] {
181        &self.bytes[HEADER_LENGTH..]
182    }
183
184    /// Returns mutable payload bytes following the fixed Ethernet II header.
185    ///
186    /// This mutably borrows the data field after the type field in RFC 894's
187    /// encapsulation: <https://www.rfc-editor.org/rfc/rfc894>.
188    #[inline]
189    pub fn payload_mut(&mut self) -> &mut [u8] {
190        &mut self.bytes[HEADER_LENGTH..]
191    }
192
193    /// Returns all represented frame bytes.
194    ///
195    /// The represented order is destination, source, type, then payload as described by
196    /// [RFC 894](https://www.rfc-editor.org/rfc/rfc894).
197    #[inline]
198    pub fn as_bytes(&self) -> &[u8] {
199        self.bytes
200    }
201
202    /// Returns all represented mutable frame bytes.
203    ///
204    /// The represented order is destination, source, type, then payload as described by
205    /// [RFC 894](https://www.rfc-editor.org/rfc/rfc894).
206    #[inline]
207    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
208        self.bytes
209    }
210}
211
212fn validate_frame_length(available: usize) -> Result<(), ParseError> {
213    if available < HEADER_LENGTH {
214        return Err(ParseError::Truncated {
215            minimum: HEADER_LENGTH,
216            available,
217        });
218    }
219    Ok(())
220}