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)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub struct Address(pub [u8; 6]);
30
31impl Address {
32 pub const BROADCAST: Address = Address([0xff; 6]);
34
35 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 pub const fn as_bytes(&self) -> &[u8] {
47 &self.0
48 }
49
50 pub fn is_unicast(&self) -> bool {
52 !(self.is_broadcast() || self.is_multicast())
53 }
54
55 pub fn is_broadcast(&self) -> bool {
57 *self == Self::BROADCAST
58 }
59
60 pub const fn is_multicast(&self) -> bool {
62 self.0[0] & 0x01 != 0
63 }
64
65 pub const fn is_local(&self) -> bool {
67 self.0[0] & 0x02 != 0
68 }
69}
70
71impl fmt::Display for Address {
72 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#[derive(Debug, Clone)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85pub struct Frame<T: AsRef<[u8]>> {
86 buffer: T,
87}
88
89mod 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
98pub const HEADER_LEN: usize = field::PAYLOAD.start;
100
101impl<T: AsRef<[u8]>> Frame<T> {
102 pub const fn new_unchecked(buffer: T) -> Frame<T> {
104 Frame { buffer }
105 }
106
107 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 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 pub fn into_inner(self) -> T {
130 self.buffer
131 }
132
133 pub const fn header_len() -> usize {
135 HEADER_LEN
136 }
137
138 pub const fn buffer_len(payload_len: usize) -> usize {
141 HEADER_LEN + payload_len
142 }
143
144 #[inline]
146 pub fn dst_addr(&self) -> Address {
147 let data = self.buffer.as_ref();
148 Address::from_bytes(&data[field::DESTINATION])
149 }
150
151 #[inline]
153 pub fn src_addr(&self) -> Address {
154 let data = self.buffer.as_ref();
155 Address::from_bytes(&data[field::SOURCE])
156 }
157
158 #[inline]
160 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
167impl<'a, T: AsRef<[u8]> + ?Sized> Frame<&'a T> {
168 #[inline]
170 pub fn payload(&self) -> &'a [u8] {
171 let data = self.buffer.as_ref();
172 &data[field::PAYLOAD]
173 }
174}
175
176impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
177 #[inline]
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 #[inline]
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 #[inline]
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 #[inline]
200 pub fn payload_mut(&mut self) -> &mut [u8] {
201 let data = self.buffer.as_mut();
202 &mut data[field::PAYLOAD]
203 }
204}
205
206impl<T: AsRef<[u8]>> AsRef<[u8]> for Frame<T> {
207 fn as_ref(&self) -> &[u8] {
208 self.buffer.as_ref()
209 }
210}
211
212impl<T: AsRef<[u8]>> fmt::Display for Frame<T> {
213 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
224use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
225
226impl<T: AsRef<[u8]>> PrettyPrint for Frame<T> {
227 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#[derive(Debug, PartialEq, Eq, Clone, Copy)]
261#[cfg_attr(feature = "defmt", derive(defmt::Format))]
262pub struct Repr {
263 pub src_addr: Address,
264 pub dst_addr: Address,
265 pub ethertype: EtherType,
266}
267
268impl Repr {
269 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 pub const fn buffer_len(&self) -> usize {
281 HEADER_LEN
282 }
283
284 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)]
293mod test {
294 use super::*;
297
298 #[test]
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")]
309mod test_ipv4 {
310 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]
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]
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")]
357mod test_ipv6 {
358 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]
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]
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}