Skip to main content

strat9_kernel/hardware/nic/
mod.rs

1//! Network driver integration layer.
2//!
3//! Thin kernel glue that wires external crates (`net-core`, `e1000`, …)
4//! to kernel services (PCI, DMA allocator, VFS schemes).
5
6pub mod e1000_drv;
7pub mod e1000e_drv;
8pub mod igc_drv;
9pub mod pcnet_drv;
10pub mod rtl8139_drv;
11pub mod scheme;
12pub mod virtio_net;
13
14pub use net_core::{NetError, NetworkDevice, MTU};
15
16use alloc::{format, string::String, sync::Arc, vec::Vec};
17use spin::RwLock;
18
19struct NetDeviceEntry {
20    iface: String,
21    device: Arc<dyn NetworkDevice>,
22}
23
24static NET_DEVICES: RwLock<Vec<NetDeviceEntry>> = RwLock::new(Vec::new());
25
26/// Map a driver name to a FreeBSD-style interface prefix.
27///
28/// | Driver          | Prefix   | Example |
29/// |-----------------|----------|---------|
30/// | e1000 / Intel   | `em`     | `em0`   |
31/// | VirtIO-net      | `vtnet`  | `vtnet0`|
32/// | (other)         | `net`    | `net0`  |
33fn bsd_prefix(driver_name: &str) -> &'static str {
34    let lower = driver_name.as_bytes();
35    // Match common patterns without pulling in a full lowercase comparison
36    if lower.len() >= 4
37        && (lower[0] | 0x20) == b'e'
38        && (lower[1] | 0x20) == b'1'
39        && lower[2] == b'0'
40        && lower[3] == b'0'
41    {
42        return "em"; // Intel PRO/1000 family
43    }
44    if lower.len() >= 6
45        && (lower[0] | 0x20) == b'v'
46        && (lower[1] | 0x20) == b'i'
47        && (lower[2] | 0x20) == b'r'
48        && (lower[3] | 0x20) == b't'
49        && (lower[4] | 0x20) == b'i'
50        && (lower[5] | 0x20) == b'o'
51    {
52        return "vtnet"; // VirtIO
53    }
54    "net" // fallback
55}
56
57/// Counters per-prefix so that `em0`, `em1`, `vtnet0` are independent.
58static PREFIX_COUNTERS: RwLock<Vec<(String, usize)>> = RwLock::new(Vec::new());
59
60/// Performs the next index for operation.
61fn next_index_for(prefix: &str) -> usize {
62    let mut counters = PREFIX_COUNTERS.write();
63    for entry in counters.iter_mut() {
64        if entry.0 == prefix {
65            let idx = entry.1;
66            entry.1 += 1;
67            return idx;
68        }
69    }
70    counters.push((String::from(prefix), 1));
71    0
72}
73
74/// Performs the register device operation.
75pub fn register_device(device: Arc<dyn NetworkDevice>) -> String {
76    let prefix = bsd_prefix(device.name());
77    let idx = next_index_for(prefix);
78    let iface = format!("{}{}", prefix, idx);
79    let mac = device.mac_address();
80    log::info!(
81        "[net] {} -> {} (MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x})",
82        device.name(),
83        iface,
84        mac[0],
85        mac[1],
86        mac[2],
87        mac[3],
88        mac[4],
89        mac[5],
90    );
91    let mut devs = NET_DEVICES.write();
92    devs.push(NetDeviceEntry {
93        iface: iface.clone(),
94        device,
95    });
96    iface
97}
98
99/// Returns device.
100pub fn get_device(name: &str) -> Option<Arc<dyn NetworkDevice>> {
101    NET_DEVICES
102        .read()
103        .iter()
104        .find(|e| e.iface == name)
105        .map(|e| e.device.clone())
106}
107
108/// Returns default device.
109pub fn get_default_device() -> Option<Arc<dyn NetworkDevice>> {
110    NET_DEVICES.read().first().map(|e| e.device.clone())
111}
112
113/// Performs the list interfaces operation.
114pub fn list_interfaces() -> Vec<String> {
115    NET_DEVICES.read().iter().map(|e| e.iface.clone()).collect()
116}
117
118/// Performs the init operation.
119pub fn init() {
120    log::info!("[net] Scanning for network devices...");
121    // Probe modern Intel first, then legacy fallback.
122    e1000e_drv::init();
123    igc_drv::init();
124    e1000_drv::init();
125    pcnet_drv::init();
126    rtl8139_drv::init();
127    virtio_net::init();
128    if let Err(e) = scheme::register_net_scheme() {
129        log::warn!("[net] Failed to register net scheme: {:?}", e);
130    }
131}