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 pub fn as_eui_64(&self) -> Option<[u8; 8]> {
71 let mut bytes = [0; 8];
72 bytes[0..3].copy_from_slice(&self.0[0..3]);
73 bytes[3] = 0xFF;
74 bytes[4] = 0xFE;
75 bytes[5..8].copy_from_slice(&self.0[3..6]);
76 bytes[0] ^= 1 << 1;
77 Some(bytes)
78 }
79}
80
81impl fmt::Display for Address {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 let bytes = self.0;
84 write!(
85 f,
86 "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
87 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]
88 )
89 }
90}
91
92#[cfg(feature = "defmt")]
93impl defmt::Format for Address {
94 fn format(&self, fmt: defmt::Formatter) {
95 let bytes = self.0;
96 defmt::write!(
97 fmt,
98 "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
99 bytes[0],
100 bytes[1],
101 bytes[2],
102 bytes[3],
103 bytes[4],
104 bytes[5]
105 )
106 }
107}
108
109#[derive(Debug, Clone)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub struct Frame<T: AsRef<[u8]>> {
113 buffer: T,
114}
115
116mod field {
117 use crate::wire::field::*;
118
119 pub const DESTINATION: Field = 0..6;
120 pub const SOURCE: Field = 6..12;
121 pub const ETHERTYPE: Field = 12..14;
122 pub const PAYLOAD: Rest = 14..;
123}
124
125pub const HEADER_LEN: usize = field::PAYLOAD.start;
127
128impl<T: AsRef<[u8]>> Frame<T> {
129 pub const fn new_unchecked(buffer: T) -> Frame<T> {
131 Frame { buffer }
132 }
133
134 pub fn new_checked(buffer: T) -> Result<Frame<T>> {
139 let packet = Self::new_unchecked(buffer);
140 packet.check_len()?;
141 Ok(packet)
142 }
143
144 pub fn check_len(&self) -> Result<()> {
147 let len = self.buffer.as_ref().len();
148 if len < HEADER_LEN { Err(Error) } else { Ok(()) }
149 }
150
151 pub fn into_inner(self) -> T {
153 self.buffer
154 }
155
156 pub const fn header_len() -> usize {
158 HEADER_LEN
159 }
160
161 pub const fn buffer_len(payload_len: usize) -> usize {
164 HEADER_LEN + payload_len
165 }
166
167 #[inline]
169 pub fn dst_addr(&self) -> Address {
170 let data = self.buffer.as_ref();
171 Address::from_bytes(&data[field::DESTINATION])
172 }
173
174 #[inline]
176 pub fn src_addr(&self) -> Address {
177 let data = self.buffer.as_ref();
178 Address::from_bytes(&data[field::SOURCE])
179 }
180
181 #[inline]
183 pub fn ethertype(&self) -> EtherType {
184 let data = self.buffer.as_ref();
185 let raw = NetworkEndian::read_u16(&data[field::ETHERTYPE]);
186 EtherType::from(raw)
187 }
188}
189
190impl<'a, T: AsRef<[u8]> + ?Sized> Frame<&'a T> {
191 #[inline]
193 pub fn payload(&self) -> &'a [u8] {
194 let data = self.buffer.as_ref();
195 &data[field::PAYLOAD]
196 }
197}
198
199impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
200 #[inline]
202 pub fn set_dst_addr(&mut self, value: Address) {
203 let data = self.buffer.as_mut();
204 data[field::DESTINATION].copy_from_slice(value.as_bytes())
205 }
206
207 #[inline]
209 pub fn set_src_addr(&mut self, value: Address) {
210 let data = self.buffer.as_mut();
211 data[field::SOURCE].copy_from_slice(value.as_bytes())
212 }
213
214 #[inline]
216 pub fn set_ethertype(&mut self, value: EtherType) {
217 let data = self.buffer.as_mut();
218 NetworkEndian::write_u16(&mut data[field::ETHERTYPE], value.into())
219 }
220
221 #[inline]
223 pub fn payload_mut(&mut self) -> &mut [u8] {
224 let data = self.buffer.as_mut();
225 &mut data[field::PAYLOAD]
226 }
227}
228
229impl<T: AsRef<[u8]>> AsRef<[u8]> for Frame<T> {
230 fn as_ref(&self) -> &[u8] {
231 self.buffer.as_ref()
232 }
233}
234
235impl<T: AsRef<[u8]>> fmt::Display for Frame<T> {
236 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237 write!(
238 f,
239 "EthernetII src={} dst={} type={}",
240 self.src_addr(),
241 self.dst_addr(),
242 self.ethertype()
243 )
244 }
245}
246
247use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
248
249impl<T: AsRef<[u8]>> PrettyPrint for Frame<T> {
250 fn pretty_print(
251 buffer: &dyn AsRef<[u8]>,
252 f: &mut fmt::Formatter,
253 indent: &mut PrettyIndent,
254 ) -> fmt::Result {
255 let frame = match Frame::new_checked(buffer) {
256 Err(err) => return write!(f, "{indent}({err})"),
257 Ok(frame) => frame,
258 };
259 write!(f, "{indent}{frame}")?;
260
261 match frame.ethertype() {
262 #[cfg(feature = "proto-ipv4")]
263 EtherType::Arp => {
264 indent.increase(f)?;
265 super::ArpPacket::<&[u8]>::pretty_print(&frame.payload(), f, indent)
266 }
267 #[cfg(feature = "proto-ipv4")]
268 EtherType::Ipv4 => {
269 indent.increase(f)?;
270 super::Ipv4Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
271 }
272 #[cfg(feature = "proto-ipv6")]
273 EtherType::Ipv6 => {
274 indent.increase(f)?;
275 super::Ipv6Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
276 }
277 _ => Ok(()),
278 }
279 }
280}
281
282#[derive(Debug, PartialEq, Eq, Clone, Copy)]
284#[cfg_attr(feature = "defmt", derive(defmt::Format))]
285pub struct Repr {
286 pub src_addr: Address,
287 pub dst_addr: Address,
288 pub ethertype: EtherType,
289}
290
291impl Repr {
292 pub fn parse<T: AsRef<[u8]> + ?Sized>(frame: &Frame<&T>) -> Result<Repr> {
294 frame.check_len()?;
295 Ok(Repr {
296 src_addr: frame.src_addr(),
297 dst_addr: frame.dst_addr(),
298 ethertype: frame.ethertype(),
299 })
300 }
301
302 pub const fn buffer_len(&self) -> usize {
304 HEADER_LEN
305 }
306
307 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>) {
309 assert!(frame.buffer.as_ref().len() >= self.buffer_len());
310 frame.set_src_addr(self.src_addr);
311 frame.set_dst_addr(self.dst_addr);
312 frame.set_ethertype(self.ethertype);
313 }
314}
315
316#[cfg(test)]
317mod test {
318 use super::*;
321
322 #[test]
323 fn test_broadcast() {
324 assert!(Address::BROADCAST.is_broadcast());
325 assert!(!Address::BROADCAST.is_unicast());
326 assert!(Address::BROADCAST.is_multicast());
327 assert!(Address::BROADCAST.is_local());
328 }
329}
330
331#[cfg(test)]
332#[cfg(feature = "proto-ipv4")]
333mod test_ipv4 {
334 use super::*;
336
337 static FRAME_BYTES: [u8; 64] = [
338 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x08, 0x00, 0xaa,
339 0x00, 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, 0xff,
343 ];
344
345 static PAYLOAD_BYTES: [u8; 50] = [
346 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0xff,
350 ];
351
352 #[test]
353 fn test_deconstruct() {
354 let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
355 assert_eq!(
356 frame.dst_addr(),
357 Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
358 );
359 assert_eq!(
360 frame.src_addr(),
361 Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])
362 );
363 assert_eq!(frame.ethertype(), EtherType::Ipv4);
364 assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
365 }
366
367 #[test]
368 fn test_construct() {
369 let mut bytes = vec![0xa5; 64];
370 let mut frame = Frame::new_unchecked(&mut bytes);
371 frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
372 frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
373 frame.set_ethertype(EtherType::Ipv4);
374 frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
375 assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
376 }
377}
378
379#[cfg(test)]
380#[cfg(feature = "proto-ipv6")]
381mod test_ipv6 {
382 use super::*;
384
385 static FRAME_BYTES: [u8; 54] = [
386 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x86, 0xdd, 0x60,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
390 ];
391
392 static PAYLOAD_BYTES: [u8; 40] = [
393 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
396 ];
397
398 #[test]
399 fn test_deconstruct() {
400 let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
401 assert_eq!(
402 frame.dst_addr(),
403 Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
404 );
405 assert_eq!(
406 frame.src_addr(),
407 Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])
408 );
409 assert_eq!(frame.ethertype(), EtherType::Ipv6);
410 assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
411 }
412
413 #[test]
414 fn test_construct() {
415 let mut bytes = vec![0xa5; 54];
416 let mut frame = Frame::new_unchecked(&mut bytes);
417 frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
418 frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
419 frame.set_ethertype(EtherType::Ipv6);
420 assert_eq!(PAYLOAD_BYTES.len(), frame.payload_mut().len());
421 frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
422 assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
423 }
424}