1 use byteorder::{ByteOrder, NetworkEndian};
2 use core::fmt;
3 
4 use super::{Error, Result};
5 
6 enum_with_unknown! {
7     /// Ethernet protocol type.
8     pub enum EtherType(u16) {
9         Ipv4 = 0x0800,
10         Arp  = 0x0806,
11         Ipv6 = 0x86DD
12     }
13 }
14 
15 impl fmt::Display for EtherType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result16     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 /// A six-octet Ethernet II address.
27 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
28 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
29 pub struct Address(pub [u8; 6]);
30 
31 impl Address {
32     /// The broadcast address.
33     pub const BROADCAST: Address = Address([0xff; 6]);
34 
35     /// Construct an Ethernet address from a sequence of octets, in big-endian.
36     ///
37     /// # Panics
38     /// The function panics if `data` is not six octets long.
from_bytes(data: &[u8]) -> Address39     pub fn from_bytes(data: &[u8]) -> Address {
40         let mut bytes = [0; 6];
41         bytes.copy_from_slice(data);
42         Address(bytes)
43     }
44 
45     /// Return an Ethernet address as a sequence of octets, in big-endian.
as_bytes(&self) -> &[u8]46     pub const fn as_bytes(&self) -> &[u8] {
47         &self.0
48     }
49 
50     /// Query whether the address is an unicast address.
is_unicast(&self) -> bool51     pub fn is_unicast(&self) -> bool {
52         !(self.is_broadcast() || self.is_multicast())
53     }
54 
55     /// Query whether this address is the broadcast address.
is_broadcast(&self) -> bool56     pub fn is_broadcast(&self) -> bool {
57         *self == Self::BROADCAST
58     }
59 
60     /// Query whether the "multicast" bit in the OUI is set.
is_multicast(&self) -> bool61     pub const fn is_multicast(&self) -> bool {
62         self.0[0] & 0x01 != 0
63     }
64 
65     /// Query whether the "locally administered" bit in the OUI is set.
is_local(&self) -> bool66     pub const fn is_local(&self) -> bool {
67         self.0[0] & 0x02 != 0
68     }
69 }
70 
71 impl fmt::Display for Address {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result72     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73         let bytes = self.0;
74         write!(
75             f,
76             "{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
77             bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]
78         )
79     }
80 }
81 
82 /// A read/write wrapper around an Ethernet II frame buffer.
83 #[derive(Debug, Clone)]
84 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
85 pub struct Frame<T: AsRef<[u8]>> {
86     buffer: T,
87 }
88 
89 mod field {
90     use crate::wire::field::*;
91 
92     pub const DESTINATION: Field = 0..6;
93     pub const SOURCE: Field = 6..12;
94     pub const ETHERTYPE: Field = 12..14;
95     pub const PAYLOAD: Rest = 14..;
96 }
97 
98 /// The Ethernet header length
99 pub const HEADER_LEN: usize = field::PAYLOAD.start;
100 
101 impl<T: AsRef<[u8]>> Frame<T> {
102     /// Imbue a raw octet buffer with Ethernet frame structure.
new_unchecked(buffer: T) -> Frame<T>103     pub const fn new_unchecked(buffer: T) -> Frame<T> {
104         Frame { buffer }
105     }
106 
107     /// Shorthand for a combination of [new_unchecked] and [check_len].
108     ///
109     /// [new_unchecked]: #method.new_unchecked
110     /// [check_len]: #method.check_len
new_checked(buffer: T) -> Result<Frame<T>>111     pub fn new_checked(buffer: T) -> Result<Frame<T>> {
112         let packet = Self::new_unchecked(buffer);
113         packet.check_len()?;
114         Ok(packet)
115     }
116 
117     /// Ensure that no accessor method will panic if called.
118     /// Returns `Err(Error)` if the buffer is too short.
check_len(&self) -> Result<()>119     pub fn check_len(&self) -> Result<()> {
120         let len = self.buffer.as_ref().len();
121         if len < HEADER_LEN {
122             Err(Error)
123         } else {
124             Ok(())
125         }
126     }
127 
128     /// Consumes the frame, returning the underlying buffer.
into_inner(self) -> T129     pub fn into_inner(self) -> T {
130         self.buffer
131     }
132 
133     /// Return the length of a frame header.
header_len() -> usize134     pub const fn header_len() -> usize {
135         HEADER_LEN
136     }
137 
138     /// Return the length of a buffer required to hold a packet with the payload
139     /// of a given length.
buffer_len(payload_len: usize) -> usize140     pub const fn buffer_len(payload_len: usize) -> usize {
141         HEADER_LEN + payload_len
142     }
143 
144     /// Return the destination address field.
145     #[inline]
dst_addr(&self) -> Address146     pub fn dst_addr(&self) -> Address {
147         let data = self.buffer.as_ref();
148         Address::from_bytes(&data[field::DESTINATION])
149     }
150 
151     /// Return the source address field.
152     #[inline]
src_addr(&self) -> Address153     pub fn src_addr(&self) -> Address {
154         let data = self.buffer.as_ref();
155         Address::from_bytes(&data[field::SOURCE])
156     }
157 
158     /// Return the EtherType field, without checking for 802.1Q.
159     #[inline]
ethertype(&self) -> EtherType160     pub fn ethertype(&self) -> EtherType {
161         let data = self.buffer.as_ref();
162         let raw = NetworkEndian::read_u16(&data[field::ETHERTYPE]);
163         EtherType::from(raw)
164     }
165 }
166 
167 impl<'a, T: AsRef<[u8]> + ?Sized> Frame<&'a T> {
168     /// Return a pointer to the payload, without checking for 802.1Q.
169     #[inline]
payload(&self) -> &'a [u8]170     pub fn payload(&self) -> &'a [u8] {
171         let data = self.buffer.as_ref();
172         &data[field::PAYLOAD]
173     }
174 }
175 
176 impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
177     /// Set the destination address field.
178     #[inline]
set_dst_addr(&mut self, value: Address)179     pub fn set_dst_addr(&mut self, value: Address) {
180         let data = self.buffer.as_mut();
181         data[field::DESTINATION].copy_from_slice(value.as_bytes())
182     }
183 
184     /// Set the source address field.
185     #[inline]
set_src_addr(&mut self, value: Address)186     pub fn set_src_addr(&mut self, value: Address) {
187         let data = self.buffer.as_mut();
188         data[field::SOURCE].copy_from_slice(value.as_bytes())
189     }
190 
191     /// Set the EtherType field.
192     #[inline]
set_ethertype(&mut self, value: EtherType)193     pub fn set_ethertype(&mut self, value: EtherType) {
194         let data = self.buffer.as_mut();
195         NetworkEndian::write_u16(&mut data[field::ETHERTYPE], value.into())
196     }
197 
198     /// Return a mutable pointer to the payload.
199     #[inline]
payload_mut(&mut self) -> &mut [u8]200     pub fn payload_mut(&mut self) -> &mut [u8] {
201         let data = self.buffer.as_mut();
202         &mut data[field::PAYLOAD]
203     }
204 }
205 
206 impl<T: AsRef<[u8]>> AsRef<[u8]> for Frame<T> {
as_ref(&self) -> &[u8]207     fn as_ref(&self) -> &[u8] {
208         self.buffer.as_ref()
209     }
210 }
211 
212 impl<T: AsRef<[u8]>> fmt::Display for Frame<T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result213     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214         write!(
215             f,
216             "EthernetII src={} dst={} type={}",
217             self.src_addr(),
218             self.dst_addr(),
219             self.ethertype()
220         )
221     }
222 }
223 
224 use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
225 
226 impl<T: AsRef<[u8]>> PrettyPrint for Frame<T> {
pretty_print( buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter, indent: &mut PrettyIndent, ) -> fmt::Result227     fn pretty_print(
228         buffer: &dyn AsRef<[u8]>,
229         f: &mut fmt::Formatter,
230         indent: &mut PrettyIndent,
231     ) -> fmt::Result {
232         let frame = match Frame::new_checked(buffer) {
233             Err(err) => return write!(f, "{indent}({err})"),
234             Ok(frame) => frame,
235         };
236         write!(f, "{indent}{frame}")?;
237 
238         match frame.ethertype() {
239             #[cfg(feature = "proto-ipv4")]
240             EtherType::Arp => {
241                 indent.increase(f)?;
242                 super::ArpPacket::<&[u8]>::pretty_print(&frame.payload(), f, indent)
243             }
244             #[cfg(feature = "proto-ipv4")]
245             EtherType::Ipv4 => {
246                 indent.increase(f)?;
247                 super::Ipv4Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
248             }
249             #[cfg(feature = "proto-ipv6")]
250             EtherType::Ipv6 => {
251                 indent.increase(f)?;
252                 super::Ipv6Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent)
253             }
254             _ => Ok(()),
255         }
256     }
257 }
258 
259 /// A high-level representation of an Internet Protocol version 4 packet header.
260 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
261 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
262 pub struct Repr {
263     pub src_addr: Address,
264     pub dst_addr: Address,
265     pub ethertype: EtherType,
266 }
267 
268 impl Repr {
269     /// Parse an Ethernet II frame and return a high-level representation.
parse<T: AsRef<[u8]> + ?Sized>(frame: &Frame<&T>) -> Result<Repr>270     pub fn parse<T: AsRef<[u8]> + ?Sized>(frame: &Frame<&T>) -> Result<Repr> {
271         frame.check_len()?;
272         Ok(Repr {
273             src_addr: frame.src_addr(),
274             dst_addr: frame.dst_addr(),
275             ethertype: frame.ethertype(),
276         })
277     }
278 
279     /// Return the length of a header that will be emitted from this high-level representation.
buffer_len(&self) -> usize280     pub const fn buffer_len(&self) -> usize {
281         HEADER_LEN
282     }
283 
284     /// Emit a high-level representation into an Ethernet II frame.
emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>)285     pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, frame: &mut Frame<T>) {
286         frame.set_src_addr(self.src_addr);
287         frame.set_dst_addr(self.dst_addr);
288         frame.set_ethertype(self.ethertype);
289     }
290 }
291 
292 #[cfg(test)]
293 mod test {
294     // Tests that are valid with any combination of
295     // "proto-*" features.
296     use super::*;
297 
298     #[test]
test_broadcast()299     fn test_broadcast() {
300         assert!(Address::BROADCAST.is_broadcast());
301         assert!(!Address::BROADCAST.is_unicast());
302         assert!(Address::BROADCAST.is_multicast());
303         assert!(Address::BROADCAST.is_local());
304     }
305 }
306 
307 #[cfg(test)]
308 #[cfg(feature = "proto-ipv4")]
309 mod test_ipv4 {
310     // Tests that are valid only with "proto-ipv4"
311     use super::*;
312 
313     static FRAME_BYTES: [u8; 64] = [
314         0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x08, 0x00, 0xaa,
315         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318         0x00, 0x00, 0x00, 0xff,
319     ];
320 
321     static PAYLOAD_BYTES: [u8; 50] = [
322         0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325         0x00, 0x00, 0x00, 0x00, 0xff,
326     ];
327 
328     #[test]
test_deconstruct()329     fn test_deconstruct() {
330         let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
331         assert_eq!(
332             frame.dst_addr(),
333             Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
334         );
335         assert_eq!(
336             frame.src_addr(),
337             Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])
338         );
339         assert_eq!(frame.ethertype(), EtherType::Ipv4);
340         assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
341     }
342 
343     #[test]
test_construct()344     fn test_construct() {
345         let mut bytes = vec![0xa5; 64];
346         let mut frame = Frame::new_unchecked(&mut bytes);
347         frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
348         frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
349         frame.set_ethertype(EtherType::Ipv4);
350         frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
351         assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
352     }
353 }
354 
355 #[cfg(test)]
356 #[cfg(feature = "proto-ipv6")]
357 mod test_ipv6 {
358     // Tests that are valid only with "proto-ipv6"
359     use super::*;
360 
361     static FRAME_BYTES: [u8; 54] = [
362         0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x86, 0xdd, 0x60,
363         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
366     ];
367 
368     static PAYLOAD_BYTES: [u8; 40] = [
369         0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
370         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
372     ];
373 
374     #[test]
test_deconstruct()375     fn test_deconstruct() {
376         let frame = Frame::new_unchecked(&FRAME_BYTES[..]);
377         assert_eq!(
378             frame.dst_addr(),
379             Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
380         );
381         assert_eq!(
382             frame.src_addr(),
383             Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16])
384         );
385         assert_eq!(frame.ethertype(), EtherType::Ipv6);
386         assert_eq!(frame.payload(), &PAYLOAD_BYTES[..]);
387     }
388 
389     #[test]
test_construct()390     fn test_construct() {
391         let mut bytes = vec![0xa5; 54];
392         let mut frame = Frame::new_unchecked(&mut bytes);
393         frame.set_dst_addr(Address([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
394         frame.set_src_addr(Address([0x11, 0x12, 0x13, 0x14, 0x15, 0x16]));
395         frame.set_ethertype(EtherType::Ipv6);
396         assert_eq!(PAYLOAD_BYTES.len(), frame.payload_mut().len());
397         frame.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
398         assert_eq!(&frame.into_inner()[..], &FRAME_BYTES[..]);
399     }
400 }
401