1use byteorder::{ByteOrder, NetworkEndian};
2use core::fmt;
3
4use super::{Error, Result};
5
6enum_with_unknown! {
7 pub enum EtherType(u16) {
9 Ipv4 = 0x0800,
10 Arp = 0x0806,
11 Ipv6 = 0x86DD
12 }
13}
14
15impl fmt::Display for EtherType {
16 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17 match *self {
18 EtherType::Ipv4 => write!(f, "IPv4"),
19 EtherType::Ipv6 => write!(f, "IPv6"),
20 EtherType::Arp => write!(f, "ARP"),
21 EtherType::Unknown(id) => write!(f, "0x{id:04x}"),
22 }
23 }
24}
25
26#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
28pub struct Address(pub [u8; 6]);
29
30impl Address {
31 pub const BROADCAST: Address = Address([0xff; 6]);
33
34 pub fn from_bytes(data: &[u8]) -> Address {
39 let mut bytes = [0; 6];
40 bytes.copy_from_slice(data);
41 Address(bytes)
42 }
43
44 pub const fn as_bytes(&self) -> &[u8] {
46 &self.0
47 }
48
49 pub fn is_unicast(&self) -> bool {
51 !(self.is_broadcast() || self.is_multicast())
52 }
53
54 pub fn is_broadcast(&self) -> bool {
56 *self == Self::BROADCAST
57 }
58
59 pub const fn is_multicast(&self) -> bool {
61 self.0[0] & 0x01 != 0
62 }
63
64 pub const fn is_local(&self) -> bool {
66 self.0[0] & 0x02 != 0
67 }
68}
69
70impl fmt::Display for Address {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 let bytes = self.0;
73 write!(
74 f,
75 "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
76 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]
77 )
78 }
79}
80
81#[cfg(feature = "defmt")]
82impl defmt::Format for Address {
83 fn format(&self, fmt: defmt::Formatter) {
84 let bytes = self.0;
85 defmt::write!(
86 fmt,
87 "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
88 bytes[0],
89 bytes[1],
90 bytes[2],
91 bytes[3],
92 bytes[4],
93 bytes[5]
94 )
95 }
96}
97
98#[derive(Debug, Clone)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub struct Frame<T: AsRef<[u8]>> {
102 buffer: T,
103}
104
105mod field {
106 use crate::wire::field::*;
107
108 pub const DESTINATION: Field = 0..6;
109 pub const SOURCE: Field = 6..12;
110 pub const ETHERTYPE: Field = 12..14;
111 pub const PAYLOAD: Rest = 14..;
112}
113
114pub const HEADER_LEN: usize = field::PAYLOAD.start;
116
117impl<T: AsRef<[u8]>> Frame<T> {
118 pub const fn new_unchecked(buffer: T) -> Frame<T> {
120 Frame { buffer }
121 }
122
123 pub fn new_checked(buffer: T) -> Result<Frame<T>> {
128 let packet = Self::new_unchecked(buffer);
129 packet.check_len()?;
130 Ok(packet)
131 }
132
133 pub fn check_len(&self) -> Result<()> {
136 let len = self.buffer.as_ref().len();
137 if len < HEADER_LEN {
138 Err(Error)
139 } else {
140 Ok(())
141 }
142 }
143
144 pub fn into_inner(self) -> T {
146 self.buffer
147 }
148
149 pub const fn header_len() -> usize {
151 HEADER_LEN
152 }
153
154 pub const fn buffer_len(payload_len: usize) -> usize {
157 HEADER_LEN + payload_len
158 }
159
160 #[inline]
162 pub fn dst_addr(&self) -> Address {
163 let data = self.buffer.as_ref();
164 Address::from_bytes(&data[field::DESTINATION])
165 }
166
167 #[inline]
169 pub fn src_addr(&self) -> Address {
170 let data = self.buffer.as_ref();
171 Address::from_bytes(&data[field::SOURCE])
172 }
173
174 #[inline]
176 pub fn ethertype(&self) -> EtherType {
177 let data = self.buffer.as_ref();
178 let raw = NetworkEndian::read_u16(&data[field::ETHERTYPE]);
179 EtherType::from(raw)
180 }
181}
182
183impl<'a, T: AsRef<[u8]> + ?Sized> Frame<&'a T> {
184 #[inline]
186 pub fn payload(&self) -> &'a [u8] {
187 let data = self.buffer.as_ref();
188 &data[field::PAYLOAD]
189 }
190}
191
192impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
193 #[inline]
195 pub fn set_dst_addr(&mut self, value: Address) {
196 let data = self.buffer.as_mut();
197 data[field::DESTINATION].copy_from_slice(value.as_bytes())
198 }
199
200 #[inline]
202 pub fn set_src_addr(&mut self, value: Address) {
203 let data = self.buffer.as_mut();
204 data[field::SOURCE].copy_from_slice(value.as_bytes())
205 }
206
207 #[inline]
209 pub fn set_ethertype(&mut self, value: EtherType) {
210 let data = self.buffer.as_mut();
211 NetworkEndian::write_u16(&mut data[field::ETHERTYPE], value.into())
212 }
213
214 #[inline]
216 pub fn payload_mut(&mut self) -> &mut [u8] {
217 let data = self.buffer.as_mut();
218 &mut data[field::PAYLOAD]
219 }
220}
221
222impl<T: AsRef<[u8]>> AsRef<[u8]> for Frame<T> {
223 fn as_ref(&self) -> &[u8] {
224 self.buffer.as_ref()
225 }
226}
227
228impl<T: AsRef<[u8]>> fmt::Display for Frame<T> {
229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 write!(
231 f,
232 "EthernetII src={} dst={} type={}",
233 self.src_addr(),
234 self.dst_addr(),
235 self.ethertype()
236 )
237 }
238}
239
240use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
241
242impl<T: AsRef<[u8]>> PrettyPrint for Frame<T> {
243 fn pretty_print(
244 buffer: &dyn AsRef<[u8]>,
245 f: &mut fmt::Formatter,
246 indent: &mut PrettyIndent,
247 ) -> fmt::Result {
248 let frame = match Frame::new_checked(buffer) {
249 Err(err) => return write!(f, "{indent}({err})"),
250 Ok(frame) => frame,
251 };
252 write!(f, "{indent}{frame}")?;
253
254 match frame.ethertype() {
255 #[cfg(feature = "proto-ipv4")]
256 EtherType::Arp => {
257 indent.increase(f)?;
258 super::ArpPacket::<&[u8]>::pretty_print(&frame.payload(), f, indent)
259 }
260 #[cfg(feature = "proto-ipv4")]
261 EtherType::Ipv4 => {
262 indent.increase(f)?;
263 super::Ipv4Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
264 }
265 #[cfg(feature = "proto-ipv6")]
266 EtherType::Ipv6 => {
267 indent.increase(f)?;
268 super::Ipv6Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
269 }
270 _ => Ok(()),
271 }
272 }
273}
274
275#[derive(Debug, PartialEq, Eq, Clone, Copy)]
277#[cfg_attr(feature = "defmt", derive(defmt::Format))]
278pub struct Repr {
279 pub src_addr: Address,
280 pub dst_addr: Address,
281 pub ethertype: EtherType,
282}
283
284impl Repr {
285 pub fn parse<T: AsRef<[u8]> + ?Sized>(frame: &Frame<&T>) -> Result<Repr> {
287 frame.check_len()?;
288 Ok(Repr {
289 src_addr: frame.src_addr(),
290 dst_addr: frame.dst_addr(),
291 ethertype: frame.ethertype(),
292 })
293 }
294
295 pub const fn buffer_len(&self) -> usize {
297 HEADER_LEN
298 }
299
300 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>) {
302 assert!(frame.buffer.as_ref().len() >= self.buffer_len());
303 frame.set_src_addr(self.src_addr);
304 frame.set_dst_addr(self.dst_addr);
305 frame.set_ethertype(self.ethertype);
306 }
307}
308
309#[cfg(test)]
310mod test {
311 use super::*;
314
315 #[test]
316 fn test_broadcast() {
317 assert!(Address::BROADCAST.is_broadcast());
318 assert!(!Address::BROADCAST.is_unicast());
319 assert!(Address::BROADCAST.is_multicast());
320 assert!(Address::BROADCAST.is_local());
321 }
322}
323
324#[cfg(test)]
325#[cfg(feature = "proto-ipv4")]
326mod test_ipv4 {
327 use super::*;
329
330 static FRAME_BYTES: [u8; 64] = [
331 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x08, 0x00, 0xaa,
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0xff,
336 ];
337
338 static PAYLOAD_BYTES: [u8; 50] = [
339 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0xff,
343 ];
344
345 #[test]
346 fn test_deconstruct() {
347 let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
348 assert_eq!(
349 frame.dst_addr(),
350 Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
351 );
352 assert_eq!(
353 frame.src_addr(),
354 Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])
355 );
356 assert_eq!(frame.ethertype(), EtherType::Ipv4);
357 assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
358 }
359
360 #[test]
361 fn test_construct() {
362 let mut bytes = vec![0xa5; 64];
363 let mut frame = Frame::new_unchecked(&mut bytes);
364 frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
365 frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
366 frame.set_ethertype(EtherType::Ipv4);
367 frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
368 assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
369 }
370}
371
372#[cfg(test)]
373#[cfg(feature = "proto-ipv6")]
374mod test_ipv6 {
375 use super::*;
377
378 static FRAME_BYTES: [u8; 54] = [
379 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x86, 0xdd, 0x60,
380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
383 ];
384
385 static PAYLOAD_BYTES: [u8; 40] = [
386 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
389 ];
390
391 #[test]
392 fn test_deconstruct() {
393 let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
394 assert_eq!(
395 frame.dst_addr(),
396 Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
397 );
398 assert_eq!(
399 frame.src_addr(),
400 Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])
401 );
402 assert_eq!(frame.ethertype(), EtherType::Ipv6);
403 assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
404 }
405
406 #[test]
407 fn test_construct() {
408 let mut bytes = vec![0xa5; 54];
409 let mut frame = Frame::new_unchecked(&mut bytes);
410 frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
411 frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
412 frame.set_ethertype(EtherType::Ipv6);
413 assert_eq!(PAYLOAD_BYTES.len(), frame.payload_mut().len());
414 frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
415 assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
416 }
417}