1use core::mem;
2
3#[repr(C, packed)]
6#[derive(Debug, Copy, Clone)]
7#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
8pub struct EthHdr {
9 pub dst_addr: [u8; 6],
11 pub src_addr: [u8; 6],
13 pub ether_type: u16,
16}
17
18impl EthHdr {
19 pub const LEN: usize = mem::size_of::<EthHdr>();
20
21 pub fn ether_type(&self) -> Result<EtherType, u16> {
28 EtherType::try_from(self.ether_type)
29 }
30
31 pub fn new(dst_addr: [u8; 6], src_addr: [u8; 6], eth_type: EtherType) -> Self {
41 EthHdr {
42 dst_addr,
43 src_addr,
44 ether_type: eth_type.into(),
45 }
46 }
47}
48
49#[repr(u16)]
52#[derive(PartialEq, Eq, Debug, Copy, Clone)]
53#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
54pub enum EtherType {
55 Loop = 0x0060_u16.to_be(),
56 Ipv4 = 0x0800_u16.to_be(),
57 Arp = 0x0806_u16.to_be(),
58 Ieee8021q = 0x8100_u16.to_be(),
59 Ipv6 = 0x86DD_u16.to_be(),
60 Ieee8021ad = 0x88A8_u16.to_be(),
61 Ieee8021MacSec = 0x88E5_u16.to_be(),
62 Ieee8021ah = 0x88E7_u16.to_be(),
63 Ieee8021mvrp = 0x88F5_u16.to_be(),
64 FibreChannel = 0x8906_u16.to_be(),
65 Infiniband = 0x8915_u16.to_be(),
66 LoopbackIeee8023 = 0x9000_u16.to_be(),
67 Ieee8021QinQ1 = 0x9100_u16.to_be(),
68 Ieee8021QinQ2 = 0x9200_u16.to_be(),
69 Ieee8021QinQ3 = 0x9300_u16.to_be(),
70}
71
72impl TryFrom<u16> for EtherType {
75 type Error = u16; fn try_from(value: u16) -> Result<Self, Self::Error> {
78 match value.to_be() {
79 0x0060_u16 => Ok(EtherType::Loop),
80 0x0800_u16 => Ok(EtherType::Ipv4),
81 0x0806_u16 => Ok(EtherType::Arp),
82 0x8100_u16 => Ok(EtherType::Ieee8021q),
83 0x86DD_u16 => Ok(EtherType::Ipv6),
84 0x88A8_u16 => Ok(EtherType::Ieee8021ad),
85 0x88E5_u16 => Ok(EtherType::Ieee8021MacSec),
86 0x88E7_u16 => Ok(EtherType::Ieee8021ah),
87 0x88F5_u16 => Ok(EtherType::Ieee8021mvrp),
88 0x8906_u16 => Ok(EtherType::FibreChannel),
89 0x8915_u16 => Ok(EtherType::Infiniband),
90 0x9000_u16 => Ok(EtherType::LoopbackIeee8023),
91 0x9100_u16 => Ok(EtherType::Ieee8021QinQ1),
92 0x9200_u16 => Ok(EtherType::Ieee8021QinQ2),
93 0x9300_u16 => Ok(EtherType::Ieee8021QinQ3),
94 _ => Err(value),
95 }
96 }
97}
98
99impl From<EtherType> for u16 {
102 fn from(ether_type: EtherType) -> Self {
103 ether_type as u16
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use core::mem;
111
112 const TEST_DST_MAC: [u8; 6] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55];
114 const TEST_SRC_MAC: [u8; 6] = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF];
115
116 #[test]
117 fn test_ethhdr_len() {
118 assert_eq!(EthHdr::LEN, 14);
119 assert_eq!(mem::size_of::<EthHdr>(), 14);
120 }
121
122 #[test]
123 fn test_ethhdr_new() {
124 let eth_hdr = EthHdr::new(TEST_DST_MAC, TEST_SRC_MAC, EtherType::Ipv4);
125 assert_eq!(eth_hdr.dst_addr, TEST_DST_MAC);
126 assert_eq!(eth_hdr.src_addr, TEST_SRC_MAC);
127 let ether_type_value = eth_hdr.ether_type;
128 assert_eq!(ether_type_value, EtherType::Ipv4 as u16);
129 assert_eq!(ether_type_value, 0x0800_u16.to_be());
130 }
131
132 #[test]
133 fn test_ethhdr_ether_type_method_known() {
134 let eth_hdr = EthHdr {
135 dst_addr: TEST_DST_MAC,
136 src_addr: TEST_SRC_MAC,
137 ether_type: EtherType::Ipv6 as u16,
138 };
139 assert_eq!(eth_hdr.ether_type().unwrap(), EtherType::Ipv6);
140 }
141
142 #[test]
143 fn test_ethhdr_ether_type_method_unknown() {
144 let unknown_type_val = 0x1234_u16.to_be();
145 let eth_hdr = EthHdr {
146 dst_addr: TEST_DST_MAC,
147 src_addr: TEST_SRC_MAC,
148 ether_type: unknown_type_val,
149 };
150 assert_eq!(eth_hdr.ether_type().unwrap_err(), unknown_type_val);
151 }
152
153 #[test]
154 fn test_ethertype_try_from_u16_known() {
155 let ipv4_val = 0x0800_u16.to_be();
156 assert_eq!(EtherType::try_from(ipv4_val), Ok(EtherType::Ipv4));
157
158 let ipv6_val = 0x86DD_u16.to_be();
159 assert_eq!(EtherType::try_from(ipv6_val), Ok(EtherType::Ipv6));
160
161 let arp_val = 0x0806_u16.to_be();
162 assert_eq!(EtherType::try_from(arp_val), Ok(EtherType::Arp));
163 }
164
165 #[test]
166 fn test_ethertype_try_from_u16_unknown() {
167 let unknown_val = 0x1234_u16.to_be();
168 assert_eq!(EtherType::try_from(unknown_val), Err(unknown_val));
169 }
170
171 #[test]
172 fn test_u16_from_ethertype() {
173 assert_eq!(u16::from(EtherType::Ipv4), 0x0800_u16.to_be());
174 assert_eq!(u16::from(EtherType::Arp), 0x0806_u16.to_be());
175 assert_eq!(u16::from(EtherType::Ipv6), 0x86DD_u16.to_be());
176 assert_eq!(u16::from(EtherType::Loop), 0x0060_u16.to_be());
177 }
178
179 #[test]
180 fn test_ethertype_variants_unique_values() {
181 let all_types = [
182 EtherType::Loop,
183 EtherType::Ipv4,
184 EtherType::Arp,
185 EtherType::Ieee8021q,
186 EtherType::Ipv6,
187 EtherType::Ieee8021ad,
188 EtherType::Ieee8021MacSec,
189 EtherType::Ieee8021ah,
190 EtherType::Ieee8021mvrp,
191 EtherType::FibreChannel,
192 EtherType::Infiniband,
193 EtherType::LoopbackIeee8023,
194 EtherType::Ieee8021QinQ1,
195 EtherType::Ieee8021QinQ2,
196 EtherType::Ieee8021QinQ3,
197 ];
198
199 for i in 0..all_types.len() {
200 for j in (i + 1)..all_types.len() {
201 let val_i = all_types[i] as u16;
203 let val_j = all_types[j] as u16;
204 assert_ne!(
205 val_i, val_j,
206 "Duplicate EtherType value found: {:?} and {:?} both have value {:#06x}",
207 all_types[i], all_types[j], val_i
208 );
209 }
210 }
211 }
212}