1use crate::{EtherType, MacAddr};
2use core::fmt;
3
4#[repr(transparent)]
25pub struct Frame(pub [u8]);
26
27impl Frame {
28 #[inline]
30 pub fn from_slice(b: &[u8]) -> &Frame {
31 unsafe { &*(b as *const [u8] as *const Frame) }
34 }
35
36 #[inline]
38 pub fn from_mut(b: &mut [u8]) -> &mut Frame {
39 unsafe { &mut *(b as *mut [u8] as *mut Frame) }
41 }
42
43 #[inline]
45 pub fn as_bytes(&self) -> &[u8] {
46 &self.0
47 }
48
49 #[inline]
51 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
52 &mut self.0
53 }
54
55 #[inline]
57 pub fn to_vec(&self) -> Vec<u8> {
58 self.0.to_vec()
59 }
60
61 #[inline]
63 pub fn len(&self) -> usize {
64 self.0.len()
65 }
66
67 #[inline]
68 pub fn is_empty(&self) -> bool {
69 self.0.is_empty()
70 }
71
72 #[inline]
74 pub fn is_valid(&self) -> bool {
75 self.0.len() >= 14
76 }
77
78 pub fn dst_mac(&self) -> Option<MacAddr> {
80 if self.0.len() < 14 {
81 return None;
82 }
83 let mut o = [0u8; 6];
84 o.copy_from_slice(&self.0[0..6]);
85 Some(MacAddr(o))
86 }
87
88 pub fn src_mac(&self) -> Option<MacAddr> {
90 if self.0.len() < 14 {
91 return None;
92 }
93 let mut o = [0u8; 6];
94 o.copy_from_slice(&self.0[6..12]);
95 Some(MacAddr(o))
96 }
97
98 #[inline]
100 pub fn has_vlan(&self) -> bool {
101 self.0.len() >= 18 && raw_ether_type(&self.0) == EtherType::VLAN.as_u16()
102 }
103
104 pub fn vlan_id(&self) -> u16 {
106 if !self.has_vlan() {
107 return 0;
108 }
109 u16::from_be_bytes([self.0[14], self.0[15]]) & 0x0FFF
110 }
111
112 pub fn vlan_pcp(&self) -> u8 {
114 if !self.has_vlan() {
115 return 0;
116 }
117 self.0[14] >> 5
118 }
119
120 pub fn vlan_dei(&self) -> bool {
122 self.has_vlan() && self.0[14] & 0x10 != 0
123 }
124
125 pub fn vlan_tci(&self) -> Option<u16> {
127 if !self.has_vlan() {
128 return None;
129 }
130 Some(u16::from_be_bytes([self.0[14], self.0[15]]))
131 }
132
133 pub fn ether_type(&self) -> EtherType {
135 if self.0.len() < 14 {
136 return EtherType(0);
137 }
138 let et = raw_ether_type(&self.0);
139 if et == EtherType::VLAN.as_u16() && self.0.len() >= 18 {
140 return EtherType(u16::from_be_bytes([self.0[16], self.0[17]]));
141 }
142 EtherType(et)
143 }
144
145 pub fn header_len(&self) -> usize {
147 if self.has_vlan() { 18 } else { 14 }
148 }
149
150 pub fn payload(&self) -> &[u8] {
153 let hl = self.header_len();
154 if self.0.len() < hl {
155 return &[];
156 }
157 &self.0[hl..]
158 }
159
160 pub fn payload_mut(&mut self) -> &mut [u8] {
162 let hl = self.header_len();
163 if self.0.len() < hl {
164 return &mut [];
165 }
166 &mut self.0[hl..]
167 }
168
169 pub fn is_broadcast(&self) -> bool {
171 self.0.len() >= 6 && self.0[..6] == [0xff; 6]
172 }
173
174 pub fn is_multicast(&self) -> bool {
176 !self.0.is_empty() && self.0[0] & 1 != 0
177 }
178
179 pub fn set_dst_mac(&mut self, mac: MacAddr) {
181 if self.0.len() < 14 {
182 return;
183 }
184 self.0[0..6].copy_from_slice(&mac.octets());
185 }
186
187 pub fn set_src_mac(&mut self, mac: MacAddr) {
189 if self.0.len() < 14 {
190 return;
191 }
192 self.0[6..12].copy_from_slice(&mac.octets());
193 }
194}
195
196#[inline]
197fn raw_ether_type(b: &[u8]) -> u16 {
198 u16::from_be_bytes([b[12], b[13]])
199}
200
201impl core::ops::Deref for Frame {
202 type Target = [u8];
203 #[inline]
204 fn deref(&self) -> &[u8] {
205 &self.0
206 }
207}
208
209impl AsRef<[u8]> for Frame {
210 #[inline]
211 fn as_ref(&self) -> &[u8] {
212 &self.0
213 }
214}
215
216impl PartialEq for Frame {
217 #[inline]
218 fn eq(&self, other: &Frame) -> bool {
219 self.0 == other.0
220 }
221}
222
223impl Eq for Frame {}
224
225impl core::hash::Hash for Frame {
226 #[inline]
227 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
228 self.0.hash(state)
229 }
230}
231
232impl fmt::Debug for Frame {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 f.debug_struct("Frame")
235 .field("len", &self.len())
236 .field("dst", &self.dst_mac())
237 .field("src", &self.src_mac())
238 .field("ether_type", &self.ether_type())
239 .finish()
240 }
241}
242
243pub fn build_frame(dst: MacAddr, src: MacAddr, ether_type: EtherType, payload: &[u8]) -> Vec<u8> {
247 let mut v = Vec::with_capacity(14 + payload.len());
248 v.extend_from_slice(&dst.octets());
249 v.extend_from_slice(&src.octets());
250 v.extend_from_slice(ðer_type.as_u16().to_be_bytes());
251 v.extend_from_slice(payload);
252 v
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258
259 #[test]
260 fn build_and_inspect() {
261 let dst: MacAddr = "00:11:22:33:44:55".parse().unwrap();
262 let src: MacAddr = "aa:bb:cc:dd:ee:ff".parse().unwrap();
263 let payload = [1, 2, 3, 4, 5];
264 let buf = build_frame(dst, src, EtherType::IPV4, &payload);
265 let f = Frame::from_slice(&buf);
266
267 assert!(f.is_valid());
268 assert_eq!(f.dst_mac(), Some(dst));
269 assert_eq!(f.src_mac(), Some(src));
270 assert_eq!(f.ether_type(), EtherType::IPV4);
271 assert!(!f.has_vlan());
272 assert_eq!(f.vlan_tci(), None);
273 assert_eq!(f.header_len(), 14);
274 assert_eq!(f.payload(), &payload);
275 assert!(!f.is_broadcast());
276 assert!(!f.is_multicast());
277 }
278
279 #[test]
280 fn vlan_passthrough() {
281 let mut buf = Vec::new();
283 buf.extend_from_slice(&[0xff; 6]); buf.extend_from_slice(&[0u8; 6]);
285 buf.extend_from_slice(&[0x81, 0x00]); buf.extend_from_slice(&[0x00, 0x01]); buf.extend_from_slice(&[0x08, 0x00]); buf.extend_from_slice(&[0xaa, 0xbb]); let f = Frame::from_slice(&buf);
291 assert!(f.is_valid());
292 assert!(f.has_vlan());
293 assert_eq!(f.vlan_id(), 1);
294 assert_eq!(f.vlan_pcp(), 0);
295 assert!(!f.vlan_dei());
296 assert_eq!(f.vlan_tci(), Some(1));
297 assert_eq!(f.ether_type(), EtherType::IPV4);
298 assert_eq!(f.header_len(), 18);
299 assert_eq!(f.payload(), &[0xaa, 0xbb]);
300 assert!(f.is_broadcast());
301 assert!(f.is_multicast());
302 }
303
304 #[test]
305 fn short_frame_is_invalid() {
306 let buf = [0u8; 5];
307 let f = Frame::from_slice(&buf);
308 assert!(!f.is_valid());
309 assert_eq!(f.dst_mac(), None);
310 assert_eq!(f.src_mac(), None);
311 assert_eq!(f.ether_type(), EtherType(0));
312 assert_eq!(f.payload(), &[] as &[u8]);
313 }
314
315 #[test]
316 fn mutable_setters() {
317 let buf = build_frame(MacAddr::zero(), MacAddr::zero(), EtherType::IPV4, &[]);
318 let mut owned = buf;
319 let f = Frame::from_mut(&mut owned);
320
321 let m: MacAddr = "12:34:56:78:9a:bc".parse().unwrap();
322 f.set_dst_mac(m);
323 f.set_src_mac(m);
324 assert_eq!(f.dst_mac(), Some(m));
325 assert_eq!(f.src_mac(), Some(m));
326 }
327}