zero_packet/datalink/
ethernet.rs1use crate::misc::bytes_to_mac;
2use core::{fmt, str::from_utf8};
3
4pub const ETHERNET_MIN_HEADER_LENGTH: usize = 14;
6
7pub const ETHERNET_MIN_FRAME_LENGTH: usize = 64;
9
10pub const VLAN_TAG_LENGTH: usize = 4;
12
13pub const ETHERTYPE_VLAN: u16 = 0x8100;
15
16pub const ETHERTYPE_QINQ: u16 = 0x88A8;
18
19pub struct EthernetWriter<'a> {
21 pub bytes: &'a mut [u8],
22 header_len: usize,
23}
24
25impl<'a> EthernetWriter<'a> {
26 #[inline]
28 pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
29 if bytes.len() < ETHERNET_MIN_HEADER_LENGTH {
30 return Err("Slice is too short to contain an Ethernet frame.");
31 }
32
33 Ok(Self {
34 bytes,
35 header_len: ETHERNET_MIN_HEADER_LENGTH,
36 })
37 }
38
39 #[inline]
41 pub fn header_len(&self) -> usize {
42 self.header_len
43 }
44
45 #[inline]
47 pub fn set_dest_mac(&mut self, dest: &[u8; 6]) {
48 self.bytes[0] = dest[0];
49 self.bytes[1] = dest[1];
50 self.bytes[2] = dest[2];
51 self.bytes[3] = dest[3];
52 self.bytes[4] = dest[4];
53 self.bytes[5] = dest[5];
54 }
55
56 #[inline]
58 pub fn set_src_mac(&mut self, src: &[u8; 6]) {
59 self.bytes[6] = src[0];
60 self.bytes[7] = src[1];
61 self.bytes[8] = src[2];
62 self.bytes[9] = src[3];
63 self.bytes[10] = src[4];
64 self.bytes[11] = src[5];
65 }
66
67 #[inline]
71 pub fn set_ethertype(&mut self, ethertype: u16) {
72 let offset = self.header_len - ETHERNET_MIN_HEADER_LENGTH;
73 self.bytes[12 + offset] = (ethertype >> 8) as u8;
74 self.bytes[13 + offset] = (ethertype & 0xFF) as u8;
75 }
76
77 #[inline]
83 pub fn set_vlan_tag(&mut self, tpid: u16, tci: u16) -> Result<(), &'static str> {
84 if self.bytes.len() < self.header_len + VLAN_TAG_LENGTH {
85 return Err("Slice is too short to contain VLAN tagging.");
86 }
87
88 self.bytes[12] = (tpid >> 8) as u8;
89 self.bytes[13] = (tpid & 0xFF) as u8;
90 self.bytes[14] = (tci >> 8) as u8;
91 self.bytes[15] = (tci & 0xFF) as u8;
92
93 self.header_len += VLAN_TAG_LENGTH;
94
95 Ok(())
96 }
97
98 #[inline]
104 pub fn set_double_vlan_tag(
105 &mut self,
106 outer_tpid: u16,
107 outer_tci: u16,
108 inner_tpid: u16,
109 inner_tci: u16,
110 ) -> Result<(), &'static str> {
111 if self.bytes.len() < self.header_len + 2 * VLAN_TAG_LENGTH {
112 return Err("Slice is too short to contain double VLAN tagging.");
113 }
114
115 self.bytes[12] = (outer_tpid >> 8) as u8;
116 self.bytes[13] = (outer_tpid & 0xFF) as u8;
117 self.bytes[14] = (outer_tci >> 8) as u8;
118 self.bytes[15] = (outer_tci & 0xFF) as u8;
119
120 self.bytes[16] = (inner_tpid >> 8) as u8;
121 self.bytes[17] = (inner_tpid & 0xFF) as u8;
122 self.bytes[18] = (inner_tci >> 8) as u8;
123 self.bytes[19] = (inner_tci & 0xFF) as u8;
124
125 self.header_len += 2 * VLAN_TAG_LENGTH;
126
127 Ok(())
128 }
129}
130
131#[derive(PartialEq)]
133pub struct EthernetReader<'a> {
134 pub bytes: &'a [u8],
135 header_len: usize,
136}
137
138impl<'a> EthernetReader<'a> {
139 #[inline]
141 pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
142 if bytes.len() < ETHERNET_MIN_HEADER_LENGTH {
143 return Err("Slice is too short to contain an Ethernet frame.");
144 }
145
146 let header_len = Self::calculate_header_len(bytes)?;
147
148 Ok(Self { bytes, header_len })
149 }
150
151 #[inline]
155 pub fn calculate_header_len(bytes: &[u8]) -> Result<usize, &'static str> {
156 match ((bytes[12] as u16) << 8) | (bytes[13] as u16) {
158 ETHERTYPE_VLAN => {
159 if bytes.len() < ETHERNET_MIN_HEADER_LENGTH + VLAN_TAG_LENGTH {
160 return Err("Slice is too short to contain VLAN tagging.");
161 }
162
163 Ok(ETHERNET_MIN_HEADER_LENGTH + VLAN_TAG_LENGTH)
164 }
165 ETHERTYPE_QINQ => {
166 if bytes.len() < ETHERNET_MIN_HEADER_LENGTH + 2 * VLAN_TAG_LENGTH {
167 return Err("Slice is too short to contain double VLAN tagging.");
168 }
169
170 if ((bytes[16] as u16) << 8) | (bytes[17] as u16) != ETHERTYPE_VLAN {
172 return Err("Invalid double VLAN tag.");
173 }
174
175 Ok(ETHERNET_MIN_HEADER_LENGTH + 2 * VLAN_TAG_LENGTH)
176 }
177 _ => Ok(ETHERNET_MIN_HEADER_LENGTH),
178 }
179 }
180
181 #[inline]
183 pub fn is_vlan_tagged(bytes: &[u8]) -> bool {
184 ((bytes[12] as u16) << 8) | (bytes[13] as u16) == ETHERTYPE_VLAN
185 }
186
187 #[inline]
189 pub fn is_vlan_double_tagged(bytes: &[u8]) -> bool {
190 ((bytes[12] as u16) << 8) | (bytes[13] as u16) == ETHERTYPE_QINQ
191 }
192
193 #[inline]
195 pub fn dest_mac(&self) -> &[u8] {
196 &self.bytes[0..6]
197 }
198
199 #[inline]
201 pub fn src_mac(&self) -> &[u8] {
202 &self.bytes[6..12]
203 }
204
205 #[inline]
209 pub fn ethertype(&self) -> u16 {
210 let offset = self.header_len - ETHERNET_MIN_HEADER_LENGTH;
211 ((self.bytes[12 + offset] as u16) << 8) | (self.bytes[13 + offset] as u16)
212 }
213
214 #[inline]
218 pub fn vlan_tag(&self) -> Option<(u16, u16)> {
219 if !Self::is_vlan_tagged(self.bytes) {
220 return None;
221 }
222
223 let tpid = ((self.bytes[12] as u16) << 8) | (self.bytes[13] as u16);
224 let tci = ((self.bytes[14] as u16) << 8) | (self.bytes[15] as u16);
225
226 Some((tpid, tci))
227 }
228
229 #[inline]
233 pub fn double_vlan_tag(&self) -> Option<((u16, u16), (u16, u16))> {
234 if !Self::is_vlan_double_tagged(self.bytes) {
235 return None;
236 }
237
238 let outer_tpid = ((self.bytes[12] as u16) << 8) | (self.bytes[13] as u16);
239 let outer_tci = ((self.bytes[14] as u16) << 8) | (self.bytes[15] as u16);
240 let inner_tpid = ((self.bytes[16] as u16) << 8) | (self.bytes[17] as u16);
241 let inner_tci = ((self.bytes[18] as u16) << 8) | (self.bytes[19] as u16);
242
243 Some(((outer_tpid, outer_tci), (inner_tpid, inner_tci)))
244 }
245
246 #[inline]
248 pub const fn header_len(&self) -> usize {
249 self.header_len
250 }
251
252 #[inline]
254 pub fn header(&self) -> &'a [u8] {
255 &self.bytes[..self.header_len]
256 }
257
258 #[inline]
260 pub fn payload(&self) -> &[u8] {
261 &self.bytes[self.header_len..]
262 }
263}
264
265impl fmt::Debug for EthernetReader<'_> {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 let mut d_buf = [0u8; 18];
268 let d_len = bytes_to_mac(self.dest_mac(), &mut d_buf);
269 let d_hex = from_utf8(&d_buf[..d_len]).unwrap();
270 let mut s_buf = [0u8; 18];
271 let s_len = bytes_to_mac(self.src_mac(), &mut s_buf);
272 let s_hex = from_utf8(&s_buf[..s_len]).unwrap();
273 f.debug_struct("EthernetFrame")
274 .field("dest_mac", &d_hex)
275 .field("src_mac", &s_hex)
276 .field("ethertype", &self.ethertype())
277 .finish()
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use super::*;
284
285 #[test]
286 fn getters_and_setters() {
287 let mut bytes = [0u8; 14];
289
290 let src = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
292 let dest = [0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b];
293 let ethertype = 2048;
294
295 let mut writer = EthernetWriter::new(&mut bytes).unwrap();
297
298 writer.set_src_mac(&src);
300 writer.set_dest_mac(&dest);
301 writer.set_ethertype(ethertype);
302
303 let reader = EthernetReader::new(&bytes).unwrap();
305
306 assert_eq!(reader.src_mac(), src);
308 assert_eq!(reader.dest_mac(), dest);
309 assert_eq!(reader.ethertype(), ethertype);
310 }
311}