veridian_kernel/net/
ethernet.rs1#![allow(dead_code)] use alloc::vec::Vec;
10
11use crate::{error::KernelError, net::MacAddress};
12
13pub const ETHERNET_HEADER_SIZE: usize = 14;
15
16pub const ETHERNET_MIN_PAYLOAD: usize = 46;
18
19pub const ETHERNET_MAX_PAYLOAD: usize = 1500;
21
22pub const ETHERTYPE_IPV4: u16 = 0x0800;
24pub const ETHERTYPE_ARP: u16 = 0x0806;
25pub const ETHERTYPE_IPV6: u16 = 0x86DD;
26
27#[derive(Debug, Clone)]
29pub struct EthernetFrame<'a> {
30 pub dst_mac: MacAddress,
32 pub src_mac: MacAddress,
34 pub ethertype: u16,
36 pub payload: &'a [u8],
38}
39
40pub fn parse_frame(data: &[u8]) -> Result<EthernetFrame<'_>, KernelError> {
45 if data.len() < ETHERNET_HEADER_SIZE {
46 return Err(KernelError::InvalidArgument {
47 name: "ethernet_frame",
48 value: "too_short",
49 });
50 }
51
52 let mut dst = [0u8; 6];
53 let mut src = [0u8; 6];
54 dst.copy_from_slice(&data[0..6]);
55 src.copy_from_slice(&data[6..12]);
56 let ethertype = u16::from_be_bytes([data[12], data[13]]);
57
58 Ok(EthernetFrame {
59 dst_mac: MacAddress(dst),
60 src_mac: MacAddress(src),
61 ethertype,
62 payload: &data[ETHERNET_HEADER_SIZE..],
63 })
64}
65
66pub fn construct_frame(
71 dst: MacAddress,
72 src: MacAddress,
73 ethertype: u16,
74 payload: &[u8],
75) -> Vec<u8> {
76 let mut frame = Vec::with_capacity(ETHERNET_HEADER_SIZE + payload.len());
77
78 frame.extend_from_slice(&dst.0);
80 frame.extend_from_slice(&src.0);
82 frame.extend_from_slice(ðertype.to_be_bytes());
84 frame.extend_from_slice(payload);
86
87 frame
88}
89
90pub fn is_broadcast(mac: &MacAddress) -> bool {
92 *mac == MacAddress::BROADCAST
93}
94
95pub fn is_ipv6_multicast(mac: &MacAddress) -> bool {
97 mac.0[0] == 0x33 && mac.0[1] == 0x33
98}
99
100pub fn is_for_us(frame_dst: &MacAddress, our_mac: &MacAddress) -> bool {
102 *frame_dst == *our_mac || is_broadcast(frame_dst) || is_ipv6_multicast(frame_dst)
103}
104
105pub fn dispatch_frame(data: &[u8], our_mac: &MacAddress) -> Result<(), KernelError> {
109 let frame = parse_frame(data)?;
110
111 if !is_for_us(&frame.dst_mac, our_mac) {
113 return Ok(());
114 }
115
116 match frame.ethertype {
117 ETHERTYPE_ARP => {
118 super::arp::process_arp_packet(frame.payload, our_mac)?;
119 }
120 ETHERTYPE_IPV4 => {
121 if frame.payload.len() >= super::ip::Ipv4Header::MIN_SIZE {
123 let ip_header = super::ip::Ipv4Header::from_bytes(frame.payload)?;
124 let header_len = (ip_header.ihl as usize) * 4;
125 if frame.payload.len() >= header_len {
126 let ip_payload = &frame.payload[header_len..];
127 let src = super::IpAddress::V4(ip_header.source);
128 let dst = super::IpAddress::V4(ip_header.destination);
129
130 match ip_header.protocol {
131 6 => {
132 let _ = super::tcp::process_packet(src, dst, ip_payload);
134 }
135 17 => {
136 let _ = super::udp::process_packet(src, dst, ip_payload);
138 }
139 _ => {
140 }
142 }
143 }
144 }
145 }
146 ETHERTYPE_IPV6 => {
147 super::ipv6::process_packet(frame.payload)?;
149 }
150 _ => {
151 }
153 }
154
155 Ok(())
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn test_construct_and_parse() {
164 let dst = MacAddress([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
165 let src = MacAddress([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]);
166 let payload = b"Hello, Ethernet!";
167
168 let frame = construct_frame(dst, src, ETHERTYPE_IPV4, payload);
169 assert_eq!(frame.len(), ETHERNET_HEADER_SIZE + payload.len());
170
171 let parsed = parse_frame(&frame).unwrap();
172 assert_eq!(parsed.dst_mac, dst);
173 assert_eq!(parsed.src_mac, src);
174 assert_eq!(parsed.ethertype, ETHERTYPE_IPV4);
175 assert_eq!(parsed.payload, payload);
176 }
177
178 #[test]
179 fn test_parse_too_short() {
180 let short = [0u8; 10];
181 assert!(parse_frame(&short).is_err());
182 }
183
184 #[test]
185 fn test_is_broadcast() {
186 assert!(is_broadcast(&MacAddress::BROADCAST));
187 assert!(!is_broadcast(&MacAddress::ZERO));
188 }
189}