1use alloc::vec::Vec;
4
5use crate::types::EtherType;
6use crate::util::{read_u16be, write_u16be};
7
8pub const ETHER_HEADER_LEN: usize = 14;
10
11#[derive(Debug, Clone)]
16pub struct EthernetPacket<'a> {
17 buf: &'a [u8],
18}
19
20impl<'a> EthernetPacket<'a> {
21 #[inline]
25 pub fn new(buf: &'a [u8]) -> Option<Self> {
26 if buf.len() < ETHER_HEADER_LEN {
27 return None;
28 }
29 Some(Self { buf })
30 }
31
32 #[inline]
34 pub fn dst_mac(&self) -> [u8; 6] {
35 self.buf[..6].try_into().unwrap()
36 }
37
38 #[inline]
40 pub fn src_mac(&self) -> [u8; 6] {
41 self.buf[6..12].try_into().unwrap()
42 }
43
44 #[inline]
46 pub fn ethertype(&self) -> EtherType {
47 EtherType::from(read_u16be(&self.buf[12..14]))
48 }
49
50 #[inline]
52 pub fn raw_ethertype(&self) -> u16 {
53 read_u16be(&self.buf[12..14])
54 }
55
56 #[inline]
58 pub fn payload(&self) -> &'a [u8] {
59 &self.buf[ETHER_HEADER_LEN..]
60 }
61}
62
63#[derive(Debug, Clone)]
69pub struct EthernetPacketBuilder {
70 buf: [u8; ETHER_HEADER_LEN],
71 payload: Option<Vec<u8>>,
72}
73
74impl Default for EthernetPacketBuilder {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80impl EthernetPacketBuilder {
81 pub fn new() -> Self {
82 Self {
83 buf: [0u8; ETHER_HEADER_LEN],
84 payload: None,
85 }
86 }
87
88 pub fn dst_mac(mut self, mac: [u8; 6]) -> Self {
89 self.buf[..6].copy_from_slice(&mac);
90 self
91 }
92
93 pub fn src_mac(mut self, mac: [u8; 6]) -> Self {
94 self.buf[6..12].copy_from_slice(&mac);
95 self
96 }
97
98 pub fn ethertype(mut self, et: EtherType) -> Self {
99 write_u16be(&mut self.buf[12..14], et.into());
100 self
101 }
102
103 pub fn raw_ethertype(mut self, et: u16) -> Self {
104 write_u16be(&mut self.buf[12..14], et);
105 self
106 }
107
108 pub fn payload(mut self, data: &[u8]) -> Self {
109 self.payload = Some(data.to_vec());
110 self
111 }
112
113 pub fn build(self) -> Vec<u8> {
115 let mut frame = self.buf.to_vec();
116 if let Some(ref p) = self.payload {
117 frame.extend_from_slice(p);
118 }
119 frame
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 const SAMPLE_FRAME: &[u8] = &[
129 0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F, 0x08, 0x00, 0x45, ];
134
135 #[test]
136 fn parse_valid_frame() {
137 let pkt = EthernetPacket::new(SAMPLE_FRAME).unwrap();
138 assert_eq!(pkt.dst_mac(), [0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E]);
139 assert_eq!(pkt.src_mac(), [0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F]);
140 assert_eq!(pkt.ethertype(), EtherType::Ipv4);
141 }
142
143 #[test]
144 fn parse_too_short() {
145 assert!(EthernetPacket::new(&[0u8; 13]).is_none());
146 assert!(EthernetPacket::new(&[]).is_none());
147 }
148
149 #[test]
150 fn parse_minimum_frame() {
151 let pkt = EthernetPacket::new(&[0u8; 14]).unwrap();
152 assert_eq!(pkt.ethertype(), EtherType::Unknown(0));
153 assert_eq!(pkt.payload().len(), 0);
154 }
155
156 #[test]
157 fn payload_slice() {
158 let pkt = EthernetPacket::new(SAMPLE_FRAME).unwrap();
159 assert_eq!(pkt.payload(), &[0x45]);
160 }
161
162 #[test]
163 fn build_and_parse_roundtrip() {
164 let frame = EthernetPacketBuilder::new()
165 .dst_mac([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])
166 .src_mac([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF])
167 .ethertype(EtherType::Arp)
168 .payload(&[0x01, 0x02, 0x03])
169 .build();
170
171 let pkt = EthernetPacket::new(&frame).unwrap();
172 assert_eq!(pkt.dst_mac(), [0x11, 0x22, 0x33, 0x44, 0x55, 0x66]);
173 assert_eq!(pkt.src_mac(), [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
174 assert_eq!(pkt.ethertype(), EtherType::Arp);
175 assert_eq!(pkt.payload(), &[0x01, 0x02, 0x03]);
176 }
177
178 #[test]
179 fn ethertype_arp() {
180 let frame = [
181 0xFFu8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 0x08, 0x06, ];
185 let pkt = EthernetPacket::new(&frame).unwrap();
186 assert_eq!(pkt.ethertype(), EtherType::Arp);
187 }
188}