kernel/network/
ethernet.rs

1//! Ethernet protocol layer
2//!
3//! This module provides Ethernet II frame handling for the network stack.
4//! It implements the NetworkLayer trait for Ethernet encapsulation/decapsulation.
5//!
6//! # Design
7//!
8//! The EthernetLayer manages:
9//! - Multiple network interfaces with their MAC addresses
10//! - Interface selection for outgoing packets
11//! - Device access for sending/receiving frames
12//!
13//! This design supports multiple network interfaces (eth0, eth1, wlan0, etc.).
14
15use alloc::collections::BTreeMap;
16use alloc::string::{String, ToString};
17use alloc::sync::Arc;
18use alloc::vec::Vec;
19use spin::RwLock;
20
21use crate::device::network::DevicePacket;
22use crate::device::network::MacAddress;
23use crate::early_println;
24use crate::network::NetworkInterface;
25use crate::network::protocol_stack::{LayerContext, NetworkLayer, NetworkLayerStats};
26use crate::network::socket::SocketError;
27
28/// Ethernet frame header (14 bytes)
29#[derive(Debug, Clone, Copy)]
30#[repr(C)]
31pub struct EthernetHeader {
32    /// Destination MAC address (6 bytes)
33    pub dest_mac: [u8; 6],
34    /// Source MAC address (6 bytes)
35    pub src_mac: [u8; 6],
36    /// EtherType (2 bytes) - protocol identifier
37    pub ether_type: u16,
38}
39
40impl EthernetHeader {
41    /// Create a new Ethernet header
42    pub fn new(dest_mac: [u8; 6], src_mac: [u8; 6], ether_type: u16) -> Self {
43        Self {
44            dest_mac,
45            src_mac,
46            ether_type,
47        }
48    }
49
50    /// Serialize header to bytes
51    pub fn to_bytes(&self) -> [u8; 14] {
52        let mut bytes = [0u8; 14];
53        bytes[0..6].copy_from_slice(&self.dest_mac);
54        bytes[6..12].copy_from_slice(&self.src_mac);
55        bytes[12..14].copy_from_slice(&self.ether_type.to_be_bytes());
56        bytes
57    }
58
59    /// Parse header from bytes
60    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
61        if bytes.len() < 14 {
62            return None;
63        }
64        let mut dest_mac = [0u8; 6];
65        let mut src_mac = [0u8; 6];
66        dest_mac.copy_from_slice(&bytes[0..6]);
67        src_mac.copy_from_slice(&bytes[6..12]);
68        let ether_type = u16::from_be_bytes([bytes[12], bytes[13]]);
69        Some(Self {
70            dest_mac,
71            src_mac,
72            ether_type,
73        })
74    }
75
76    /// Get EtherType as big-endian bytes
77    pub fn ether_type_be(&self) -> [u8; 2] {
78        self.ether_type.to_be_bytes()
79    }
80}
81
82/// Ethernet EtherType constants
83pub mod ether_type {
84    /// IPv4 protocol
85    pub const IPV4: u16 = 0x0800;
86    /// ARP protocol
87    pub const ARP: u16 = 0x0806;
88    /// IPv6 protocol
89    pub const IPV6: u16 = 0x86DD;
90    /// VLAN-tagged frame (802.1Q)
91    pub const VLAN: u16 = 0x8100;
92}
93
94/// Maximum Transmission Unit for Ethernet (standard)
95pub const ETHERNET_MTU: usize = 1500;
96
97/// Minimum Ethernet frame size (64 bytes including FCS)
98pub const ETHERNET_MIN_SIZE: usize = 64;
99
100/// Ethernet header size
101pub const ETHERNET_HEADER_SIZE: usize = 14;
102
103/// Ethernet interface information
104#[derive(Debug, Clone)]
105pub struct EthernetInterfaceInfo {
106    /// Interface name (e.g., "eth0", "wlan0")
107    pub name: String,
108    /// MAC address
109    pub mac: MacAddress,
110    /// Maximum Transmission Unit
111    pub mtu: usize,
112}
113
114/// Ethernet layer
115///
116/// Handles Ethernet II frame encapsulation and decapsulation.
117/// Manages multiple interfaces and routes frames based on EtherType field.
118pub struct EthernetLayer {
119    /// Registered interfaces: name -> info
120    interfaces: RwLock<BTreeMap<String, EthernetInterfaceInfo>>,
121    /// Interface devices: name -> device (kept separate for Arc<dyn> handling)
122    devices: RwLock<BTreeMap<String, Arc<dyn NetworkInterface>>>,
123    /// Default interface name
124    default_interface: RwLock<Option<String>>,
125    /// Protocol handlers registered by EtherType
126    protocols: RwLock<BTreeMap<u16, Arc<dyn NetworkLayer>>>,
127    /// Statistics
128    stats: RwLock<NetworkLayerStats>,
129}
130
131impl EthernetLayer {
132    /// Create a new Ethernet layer
133    pub fn new() -> Arc<Self> {
134        Arc::new(Self {
135            interfaces: RwLock::new(BTreeMap::new()),
136            devices: RwLock::new(BTreeMap::new()),
137            default_interface: RwLock::new(None),
138            protocols: RwLock::new(BTreeMap::new()),
139            stats: RwLock::new(NetworkLayerStats::default()),
140        })
141    }
142
143    /// Initialize and register the Ethernet layer with NetworkManager
144    ///
145    /// This is the first layer to be initialized as it has no dependencies.
146    /// Other layers (IPv4, ARP) will register their protocols with this layer.
147    pub fn init(network_manager: &crate::network::NetworkManager) {
148        let layer = Self::new();
149        network_manager.register_layer("ethernet", layer);
150    }
151
152    /// Register a network interface
153    pub fn register_interface(
154        &self,
155        name: &str,
156        mac: MacAddress,
157        device: Arc<dyn NetworkInterface>,
158    ) {
159        let info = EthernetInterfaceInfo {
160            name: name.to_string(),
161            mac,
162            mtu: ETHERNET_MTU,
163        };
164
165        self.interfaces.write().insert(name.to_string(), info);
166        self.devices.write().insert(name.to_string(), device);
167
168        // First interface becomes default
169        if self.default_interface.read().is_none() {
170            *self.default_interface.write() = Some(name.to_string());
171        }
172    }
173
174    /// Unregister a network interface
175    pub fn unregister_interface(&self, name: &str) {
176        self.interfaces.write().remove(name);
177        self.devices.write().remove(name);
178
179        // If this was the default, pick another
180        let mut default = self.default_interface.write();
181        if default.as_deref() == Some(name) {
182            *default = self.interfaces.read().keys().next().cloned();
183        }
184    }
185
186    /// Get interface info by name
187    pub fn get_interface(&self, name: &str) -> Option<EthernetInterfaceInfo> {
188        self.interfaces.read().get(name).cloned()
189    }
190
191    /// Get MAC address for an interface
192    pub fn get_mac(&self, name: &str) -> Option<MacAddress> {
193        self.interfaces.read().get(name).map(|i| i.mac)
194    }
195
196    /// Get default interface name
197    pub fn get_default_interface(&self) -> Option<String> {
198        self.default_interface.read().clone()
199    }
200
201    /// Set default interface
202    pub fn set_default_interface(&self, name: &str) {
203        if self.interfaces.read().contains_key(name) {
204            *self.default_interface.write() = Some(name.to_string());
205        }
206    }
207
208    /// Get all interface names
209    pub fn list_interfaces(&self) -> Vec<String> {
210        self.interfaces.read().keys().cloned().collect()
211    }
212
213    /// Get device for an interface
214    fn get_device(&self, name: &str) -> Option<Arc<dyn NetworkInterface>> {
215        self.devices.read().get(name).cloned()
216    }
217
218    /// Resolve destination MAC address for sending
219    ///
220    /// This method determines the destination MAC address for an outgoing packet:
221    /// 1. If explicit `eth_dst_mac` is in context, use it directly
222    /// 2. If destination is broadcast IP (255.255.255.255), use broadcast MAC
223    /// 3. Otherwise, look up in ARP cache (using `next_hop` if set, else `dst_ip`)
224    ///
225    /// # Arguments
226    ///
227    /// * `context` - Layer context with addressing info
228    /// * `interface` - Interface name for per-interface ARP cache lookup
229    ///
230    /// # Returns
231    ///
232    /// MAC address to use as destination, or error if resolution fails
233    fn resolve_dest_mac(
234        &self,
235        context: &LayerContext,
236        interface: &str,
237    ) -> Result<[u8; 6], SocketError> {
238        // 1. Check for explicit destination MAC in context
239        if let Some(mac_bytes) = context.get("eth_dst_mac") {
240            if mac_bytes.len() >= 6 {
241                let mut mac = [0u8; 6];
242                mac.copy_from_slice(&mac_bytes[..6]);
243                return Ok(mac);
244            }
245        }
246
247        // 2. Check if destination IP is broadcast
248        if let Some(dst_ip_bytes) = context.get("dst_ip") {
249            if dst_ip_bytes.len() >= 4 {
250                // Broadcast IP (255.255.255.255) → Broadcast MAC
251                if dst_ip_bytes[0] == 255
252                    && dst_ip_bytes[1] == 255
253                    && dst_ip_bytes[2] == 255
254                    && dst_ip_bytes[3] == 255
255                {
256                    return Ok([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
257                }
258            }
259        }
260
261        // 3. Determine which IP to resolve (next_hop from gateway, or direct dst_ip)
262        let resolve_ip = context.get("next_hop").or_else(|| context.get("dst_ip"));
263
264        if let Some(ip_bytes) = resolve_ip {
265            if ip_bytes.len() >= 4 {
266                let ip = crate::network::ipv4::Ipv4Address::from_bytes([
267                    ip_bytes[0],
268                    ip_bytes[1],
269                    ip_bytes[2],
270                    ip_bytes[3],
271                ]);
272
273                // Look up in ARP cache via NetworkManager (interface-aware)
274                if let Some(arp_layer) =
275                    crate::network::protocol_stack::get_network_manager().get_layer("arp")
276                {
277                    if let Some(arp) = arp_layer
278                        .as_any()
279                        .downcast_ref::<crate::network::arp::ArpLayer>()
280                    {
281                        // Use interface-aware lookup
282                        if let Some(mac) = arp.lookup_on_interface(interface, ip) {
283                            return Ok(mac);
284                        }
285
286                        // Not in cache - trigger ARP request
287                        early_println!(
288                            "[Ethernet] ARP cache miss for {}.{}.{}.{} on {}, need resolution",
289                            ip_bytes[0],
290                            ip_bytes[1],
291                            ip_bytes[2],
292                            ip_bytes[3],
293                            interface
294                        );
295
296                        // Trigger ARP request with interface info
297                        let mut arp_context = LayerContext::new();
298                        arp_context.set("interface", interface.as_bytes());
299                        let _ = arp.send_request(ip, &arp_context, &[]);
300
301                        return Err(SocketError::WouldBlock);
302                    }
303                }
304            }
305        }
306
307        // No way to determine destination MAC
308        early_println!("[Ethernet] Cannot resolve destination MAC: no dst_ip or eth_dst_mac");
309        Err(SocketError::NoRoute)
310    }
311
312    /// Receive a frame on a specific interface
313    ///
314    /// This method should be called by drivers to process incoming frames.
315    /// It passes the interface name to upper layers via context.
316    pub fn receive_on_interface(&self, frame: &[u8], interface: &str) -> Result<(), SocketError> {
317        if frame.len() < ETHERNET_HEADER_SIZE {
318            return Err(SocketError::InvalidPacket);
319        }
320
321        let header = EthernetHeader::from_bytes(&frame[..ETHERNET_HEADER_SIZE])
322            .ok_or(SocketError::InvalidPacket)?;
323
324        early_println!(
325            "[Ethernet] RX on {}: {} bytes (type=0x{:04X})",
326            interface,
327            frame.len(),
328            header.ether_type
329        );
330
331        let payload = &frame[ETHERNET_HEADER_SIZE..];
332
333        let mut stats = self.stats.write();
334        stats.packets_received += 1;
335        stats.bytes_received += frame.len() as u64;
336        drop(stats);
337
338        // Build context with interface info and source MAC
339        let mut context = LayerContext::new();
340        context.set("interface", interface.as_bytes());
341        context.set("eth_src_mac", &header.src_mac);
342        context.set("eth_dst_mac", &header.dest_mac);
343
344        let protocols = self.protocols.read();
345        if let Some(handler) = protocols.get(&header.ether_type) {
346            handler.receive(payload, Some(&context))
347        } else {
348            Ok(())
349        }
350    }
351}
352
353impl NetworkLayer for EthernetLayer {
354    fn register_protocol(&self, proto_num: u16, handler: Arc<dyn NetworkLayer>) {
355        self.protocols.write().insert(proto_num, handler);
356    }
357
358    fn send(
359        &self,
360        packet: &[u8],
361        context: &LayerContext,
362        _next_layers: &[Arc<dyn NetworkLayer>],
363    ) -> Result<(), SocketError> {
364        // Get interface from context, or use default
365        let interface_name = context
366            .get("interface")
367            .and_then(|b| core::str::from_utf8(b).ok())
368            .map(String::from)
369            .or_else(|| self.get_default_interface())
370            .ok_or(SocketError::NoRoute)?;
371
372        // Get source MAC from interface
373        let src_mac = self.get_mac(&interface_name).ok_or(SocketError::NoRoute)?;
374
375        // Determine destination MAC
376        let dest_mac = match self.resolve_dest_mac(context, &interface_name) {
377            Ok(mac) => mac,
378            Err(SocketError::WouldBlock) => {
379                // ARP resolution pending - queue the packet for later transmission
380                // Get the IP address we're resolving (next_hop or dst_ip)
381                let resolve_ip = context.get("next_hop").or_else(|| context.get("dst_ip"));
382                if let Some(ip_bytes) = resolve_ip {
383                    if ip_bytes.len() >= 4 {
384                        let ip = crate::network::ipv4::Ipv4Address::from_bytes([
385                            ip_bytes[0],
386                            ip_bytes[1],
387                            ip_bytes[2],
388                            ip_bytes[3],
389                        ]);
390
391                        // Queue packet in ARP layer for later transmission
392                        if let Some(arp_layer) =
393                            crate::network::protocol_stack::get_network_manager().get_layer("arp")
394                        {
395                            if let Some(arp) = arp_layer
396                                .as_any()
397                                .downcast_ref::<crate::network::arp::ArpLayer>()
398                            {
399                                early_println!(
400                                    "[Ethernet] Queuing packet ({} bytes) for ARP resolution of {}.{}.{}.{}",
401                                    packet.len(),
402                                    ip_bytes[0],
403                                    ip_bytes[1],
404                                    ip_bytes[2],
405                                    ip_bytes[3]
406                                );
407                                arp.queue_packet_on_interface(&interface_name, ip, packet.to_vec());
408                            }
409                        }
410                    }
411                }
412                // Return WouldBlock so caller knows packet is queued, not sent
413                return Err(SocketError::WouldBlock);
414            }
415            Err(e) => return Err(e),
416        };
417
418        // Get EtherType
419        let ether_type = if let Some(eth_type) = context.get("eth_type") {
420            if eth_type.len() >= 2 {
421                u16::from_be_bytes([eth_type[0], eth_type[1]])
422            } else if !eth_type.is_empty() {
423                eth_type[0] as u16
424            } else {
425                ether_type::IPV4
426            }
427        } else {
428            ether_type::IPV4
429        };
430
431        // Build frame
432        let header = EthernetHeader::new(dest_mac, *src_mac.as_bytes(), ether_type);
433        let total_size = ETHERNET_HEADER_SIZE + packet.len();
434
435        let mut frame = Vec::with_capacity(total_size);
436        frame.extend_from_slice(&header.to_bytes());
437        frame.extend_from_slice(packet);
438
439        // Pad to minimum frame size
440        let min_payload = ETHERNET_MIN_SIZE.saturating_sub(4);
441        if frame.len() < min_payload {
442            frame.resize(min_payload, 0);
443        }
444        let frame_len = frame.len();
445
446        // Send through device
447        if let Some(device) = self.get_device(&interface_name) {
448            early_println!(
449                "[Ethernet] Sending {} bytes via {} to {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X} (type=0x{:04X})",
450                frame_len,
451                interface_name,
452                dest_mac[0],
453                dest_mac[1],
454                dest_mac[2],
455                dest_mac[3],
456                dest_mac[4],
457                dest_mac[5],
458                ether_type
459            );
460            let pkt = DevicePacket::with_data(frame);
461            device.send(pkt).map_err(|e| {
462                early_println!("[Ethernet] Send failed: {}", e);
463                SocketError::Other("send failed".into())
464            })?;
465            early_println!("[Ethernet] Send succeeded");
466        } else {
467            early_println!("[Ethernet] No device for interface {}", interface_name);
468            return Err(SocketError::NoRoute);
469        }
470
471        let mut stats = self.stats.write();
472        stats.packets_sent += 1;
473        stats.bytes_sent += total_size as u64;
474
475        Ok(())
476    }
477
478    fn receive(&self, frame: &[u8], context: Option<&LayerContext>) -> Result<(), SocketError> {
479        // If context has interface, use it; otherwise use default
480        let interface = context
481            .and_then(|c| c.get("interface"))
482            .and_then(|b| core::str::from_utf8(b).ok())
483            .map(String::from)
484            .or_else(|| self.get_default_interface());
485
486        if let Some(iface) = interface {
487            self.receive_on_interface(frame, &iface)
488        } else {
489            // Fallback: receive without interface context
490            if frame.len() < ETHERNET_HEADER_SIZE {
491                return Err(SocketError::InvalidPacket);
492            }
493
494            let header = EthernetHeader::from_bytes(&frame[..ETHERNET_HEADER_SIZE])
495                .ok_or(SocketError::InvalidPacket)?;
496
497            early_println!(
498                "[Ethernet] RX: {} bytes (type=0x{:04X})",
499                frame.len(),
500                header.ether_type
501            );
502
503            let payload = &frame[ETHERNET_HEADER_SIZE..];
504
505            let mut stats = self.stats.write();
506            stats.packets_received += 1;
507            stats.bytes_received += frame.len() as u64;
508
509            let protocols = self.protocols.read();
510            if let Some(handler) = protocols.get(&header.ether_type) {
511                handler.receive(payload, None)
512            } else {
513                Ok(())
514            }
515        }
516    }
517
518    fn name(&self) -> &'static str {
519        "Ethernet"
520    }
521
522    fn stats(&self) -> NetworkLayerStats {
523        self.stats.read().clone()
524    }
525
526    fn as_any(&self) -> &dyn core::any::Any {
527        self
528    }
529}
530
531#[cfg(test)]
532mod tests {
533    use super::*;
534
535    #[test_case]
536    fn test_ethernet_header_serialization() {
537        let src_mac = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55];
538        let dest_mac = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF];
539        let ether_type = 0x0800; // IPv4
540
541        let header = EthernetHeader::new(dest_mac, src_mac, ether_type);
542        let bytes = header.to_bytes();
543
544        assert_eq!(bytes.len(), 14);
545        assert_eq!(&bytes[0..6], &dest_mac);
546        assert_eq!(&bytes[6..12], &src_mac);
547        assert_eq!(u16::from_be_bytes([bytes[12], bytes[13]]), ether_type);
548    }
549
550    #[test_case]
551    fn test_ethernet_header_parsing() {
552        let mut bytes = [0u8; 14];
553        bytes[0..6].copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
554        bytes[6..12].copy_from_slice(&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
555        bytes[12..14].copy_from_slice(&ether_type::IPV4.to_be_bytes());
556
557        let header = EthernetHeader::from_bytes(&bytes).unwrap();
558        assert_eq!(header.dest_mac, [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
559        assert_eq!(header.src_mac, [0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
560        assert_eq!(header.ether_type, 0x0800);
561    }
562
563    #[test_case]
564    fn test_ethernet_header_invalid_length() {
565        let bytes = [0u8; 10];
566        assert!(EthernetHeader::from_bytes(&bytes).is_none());
567    }
568
569    #[test_case]
570    fn test_ether_type_constants() {
571        assert_eq!(ether_type::IPV4, 0x0800);
572        assert_eq!(ether_type::ARP, 0x0806);
573        assert_eq!(ether_type::IPV6, 0x86DD);
574        assert_eq!(ether_type::VLAN, 0x8100);
575    }
576
577    #[test_case]
578    fn test_ethernet_layer_creation() {
579        let eth_layer = EthernetLayer::new();
580        // New layer has no interfaces initially
581        assert!(eth_layer.get_default_interface().is_none());
582        assert!(eth_layer.list_interfaces().is_empty());
583    }
584
585    #[test_case]
586    fn test_ethernet_layer_register_interface() {
587        let eth_layer = EthernetLayer::new();
588        let mac = MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]);
589
590        // Create a mock device - we can't easily test without one,
591        // so we test interface registration by checking get_interface
592        // Note: In real usage, you'd pass an actual Arc<dyn NetworkInterface>
593
594        // For now, test that interface info struct works
595        let info = EthernetInterfaceInfo {
596            name: "eth0".into(),
597            mac,
598            mtu: ETHERNET_MTU,
599        };
600        assert_eq!(info.name, "eth0");
601        assert_eq!(info.mac, mac);
602        assert_eq!(info.mtu, ETHERNET_MTU);
603    }
604
605    #[test_case]
606    fn test_ethernet_layer_default_interface() {
607        let eth_layer = EthernetLayer::new();
608        // Initially no default
609        assert!(eth_layer.get_default_interface().is_none());
610    }
611}