s2n_quic_core/inet/
ethernet.rs1use crate::inet::Unspecified;
5use core::fmt;
6
7const MAC_LEN: usize = 48 / 8;
21
22define_inet_type!(
23 pub struct MacAddress {
24 octets: [u8; MAC_LEN],
25 }
26);
27
28impl fmt::Debug for MacAddress {
29 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30 f.debug_tuple("MacAddress")
31 .field(&format_args!("{self}"))
32 .finish()
33 }
34}
35
36impl fmt::Display for MacAddress {
37 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
38 let [a, b, c, d, e, f] = self.octets;
39 write!(fmt, "{a:02x}:{b:02x}:{c:02x}:{d:02x}:{e:02x}:{f:02x}")
40 }
41}
42
43impl MacAddress {
44 pub const UNSPECIFIED: Self = Self {
45 octets: [0; MAC_LEN],
46 };
47}
48
49impl Unspecified for MacAddress {
50 #[inline]
51 fn is_unspecified(&self) -> bool {
52 self.octets == [0; MAC_LEN]
53 }
54}
55
56define_inet_type!(
57 pub struct EtherType {
58 id: [u8; 2],
59 }
60);
61
62impl fmt::Debug for EtherType {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 f.debug_tuple("EtherType")
65 .field(&format_args!("{self}"))
66 .finish()
67 }
68}
69
70impl fmt::Display for EtherType {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 match *self {
73 Self::IPV4 => "IPv4",
74 Self::ARP => "ARP",
75 Self::IPV6 => "IPv6",
76 Self::VLAN => "VLAN",
77 Self::PPP => "PPP",
78 Self { id: [a, b] } => return write!(f, "[unknown 0x{a:02x}{b:02x}]"),
79 }
80 .fmt(f)
81 }
82}
83
84macro_rules! impl_type {
85 ($fun:ident, $cap:ident, $val:expr) => {
86 pub const $cap: Self = Self { id: $val };
87
88 #[inline]
89 pub const fn $fun(self) -> bool {
90 matches!(self, Self::$cap)
91 }
92 };
93}
94
95impl EtherType {
96 impl_type!(is_ipv4, IPV4, [0x08, 0x00]);
100 impl_type!(is_arp, ARP, [0x08, 0x06]);
101 impl_type!(is_ipv6, IPV6, [0x86, 0xDD]);
102 impl_type!(is_ppp, PPP, [0x88, 0x0B]);
103 impl_type!(is_vlan, VLAN, [0x88, 0xA8]);
104}
105
106define_inet_type!(
122 pub struct Header {
123 destination: MacAddress,
124 source: MacAddress,
125 ethertype: EtherType,
126 }
127);
128
129impl fmt::Debug for Header {
130 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131 f.debug_struct("ethernet::Header")
132 .field("destination", &self.destination)
133 .field("source", &self.source)
134 .field("ethertype", &self.ethertype)
135 .finish()
136 }
137}
138
139impl Header {
140 #[inline]
142 pub fn swap(&mut self) {
143 core::mem::swap(&mut self.source, &mut self.destination)
144 }
145
146 #[inline]
147 pub const fn destination(&self) -> &MacAddress {
148 &self.destination
149 }
150
151 #[inline]
152 pub fn destination_mut(&mut self) -> &mut MacAddress {
153 &mut self.destination
154 }
155
156 #[inline]
157 pub const fn source(&self) -> &MacAddress {
158 &self.source
159 }
160
161 #[inline]
162 pub fn source_mut(&mut self) -> &mut MacAddress {
163 &mut self.source
164 }
165
166 #[inline]
167 pub const fn ethertype(&self) -> &EtherType {
168 &self.ethertype
169 }
170
171 #[inline]
172 pub fn ethertype_mut(&mut self) -> &mut EtherType {
173 &mut self.ethertype
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use bolero::check;
181 use s2n_codec::DecoderBuffer;
182
183 #[test]
184 #[cfg_attr(miri, ignore)]
185 fn snapshot_test() {
186 let mut buffer = vec![0u8; core::mem::size_of::<Header>()];
187 for (idx, byte) in buffer.iter_mut().enumerate() {
188 *byte = idx as u8;
189 }
190 let decoder = DecoderBuffer::new(&buffer);
191 let (header, _) = decoder.decode::<&Header>().unwrap();
192 insta::assert_debug_snapshot!("snapshot_test", header);
193
194 buffer.fill(255);
195 let decoder = DecoderBuffer::new(&buffer);
196 let (header, _) = decoder.decode::<&Header>().unwrap();
197 insta::assert_debug_snapshot!("snapshot_filled_test", header);
198 }
199
200 #[test]
201 fn header_round_trip_test() {
202 check!().for_each(|buffer| {
203 s2n_codec::assert_codec_round_trip_bytes!(Header, buffer);
204 });
205 }
206}