kernel/network/
config.rs

1//!
2//! Network configuration helpers.
3//!
4//! Applies IP/gateway/DNS/netmask settings and handles deferred IP assignment
5//! until an interface is registered.
6
7use alloc::string::String;
8use spin::Mutex;
9
10use crate::network::ipv4::{Ipv4Address, Ipv4AddressInfo};
11use crate::network::{NetworkManager, get_network_manager};
12
13#[derive(Debug, Default)]
14struct PendingNetworkConfig {
15    ip: Option<Ipv4Address>,
16    netmask: Option<Ipv4Address>,
17    iface: Option<String>,
18}
19
20static PENDING_CONFIG: Mutex<PendingNetworkConfig> = Mutex::new(PendingNetworkConfig {
21    ip: None,
22    netmask: None,
23    iface: None,
24});
25
26fn parse_ipv4(value: &str) -> Option<Ipv4Address> {
27    let mut parts = [0u8; 4];
28    let mut index = 0;
29    for part in value.split('.') {
30        if index >= parts.len() {
31            return None;
32        }
33        parts[index] = part.parse::<u8>().ok()?;
34        index += 1;
35    }
36    if index == parts.len() {
37        Some(Ipv4Address::from_bytes(parts))
38    } else {
39        None
40    }
41}
42
43fn apply_pending_ip(network_manager: &NetworkManager, pending: &mut PendingNetworkConfig) {
44    let Some(ip) = pending.ip else {
45        return;
46    };
47
48    let target = pending.iface.as_deref();
49    let interface = match target {
50        Some(name) => network_manager.get_interface(name),
51        None => network_manager.get_default_interface(),
52    };
53
54    if let Some(interface) = interface {
55        interface.set_ip_address(ip);
56        pending.ip = None;
57        if target.is_some() {
58            pending.iface = None;
59        }
60    }
61}
62
63/// Apply network configuration from the kernel command line.
64pub fn apply_cmdline_config(cmdline: &str) {
65    let mut pending = PENDING_CONFIG.lock();
66    let mut ip = None;
67    let mut iface = None;
68    let mut gw = None;
69    let mut dns = None;
70    let mut mask = None;
71
72    for token in cmdline.split_whitespace() {
73        let Some((key, value)) = token.split_once('=') else {
74            continue;
75        };
76
77        match key {
78            "ip" | "net.ip" => {
79                if value != "dhcp" {
80                    ip = parse_ipv4(value);
81                }
82            }
83            "gw" | "net.gw" => {
84                gw = parse_ipv4(value);
85            }
86            "dns" | "net.dns" => {
87                dns = parse_ipv4(value);
88            }
89            "mask" | "net.mask" | "net.netmask" => {
90                mask = parse_ipv4(value);
91            }
92            "iface" | "net.iface" => {
93                iface = Some(String::from(value));
94            }
95            _ => {}
96        }
97    }
98
99    if let Some(ip) = ip {
100        pending.ip = Some(ip);
101    }
102    if let Some(iface) = iface {
103        pending.iface = Some(iface);
104    }
105
106    let network_manager = get_network_manager();
107    let mut config = network_manager.get_config();
108    if let Some(mask) = mask {
109        config.subnet_mask = mask;
110    }
111    if let Some(dns) = dns {
112        config.dns_server = Some(dns);
113    }
114    network_manager.set_config(config);
115    if let Some(gw) = gw {
116        network_manager.set_default_gateway(gw);
117    }
118
119    apply_pending_ip(network_manager, &mut pending);
120}
121
122pub fn set_interface_ip(name: &str, ip: Ipv4Address) -> Result<(), &'static str> {
123    set_interface_ip_with_mask(name, ip, Ipv4Address::new(255, 255, 255, 0))
124}
125
126/// Set IP address with netmask on a network interface
127pub fn set_interface_ip_with_mask(
128    name: &str,
129    ip: Ipv4Address,
130    netmask: Ipv4Address,
131) -> Result<(), &'static str> {
132    let network_manager = get_network_manager();
133
134    // Ensure network stack is initialized (NetworkManager::init sets up all layers)
135    if crate::network::protocol_stack::get_network_manager()
136        .get_layer("ip")
137        .is_none()
138    {
139        // Layers are already initialized by NetworkManager::init()
140        // If not present, something is wrong with initialization order
141        return Err("Network stack not initialized");
142    }
143
144    if let Some(interface) = network_manager.get_interface(name) {
145        // Set IP on the interface object (for backward compatibility)
146        interface.set_ip_address(ip);
147
148        // Add address to Ipv4Layer
149        if let Some(ip_layer) =
150            crate::network::protocol_stack::get_network_manager().get_layer("ip")
151        {
152            if let Some(ipv4) = ip_layer
153                .as_any()
154                .downcast_ref::<crate::network::ipv4::Ipv4Layer>()
155            {
156                // Calculate broadcast address from IP and netmask
157                let broadcast = Ipv4Address::new(
158                    ip.0[0] | !netmask.0[0],
159                    ip.0[1] | !netmask.0[1],
160                    ip.0[2] | !netmask.0[2],
161                    ip.0[3] | !netmask.0[3],
162                );
163
164                let addr_info = Ipv4AddressInfo {
165                    address: ip,
166                    netmask,
167                    broadcast: Some(broadcast),
168                    is_primary: true,
169                };
170
171                // Remove old addresses and add new one
172                // (For now, just add - in future could track and replace)
173                ipv4.add_address(name, addr_info);
174
175                crate::early_println!(
176                    "[network] {} IP set to {}.{}.{}.{}/{}",
177                    name,
178                    ip.0[0],
179                    ip.0[1],
180                    ip.0[2],
181                    ip.0[3],
182                    netmask_to_prefix(netmask)
183                );
184            } else {
185                crate::early_println!("[network] set {} IP failed: no IPv4 layer", name);
186            }
187        } else {
188            crate::early_println!("[network] set {} IP failed: no IP layer", name);
189        }
190        return Ok(());
191    }
192
193    // Interface not ready yet, save for later
194    let mut pending = PENDING_CONFIG.lock();
195    pending.ip = Some(ip);
196    pending.netmask = Some(netmask);
197    pending.iface = Some(String::from(name));
198    Ok(())
199}
200
201/// Convert netmask to CIDR prefix length
202fn netmask_to_prefix(mask: Ipv4Address) -> u8 {
203    let bits = u32::from_be_bytes(mask.0);
204    bits.count_ones() as u8
205}
206
207pub fn apply_pending_ip_for_interface(name: &str) {
208    let mut pending = PENDING_CONFIG.lock();
209
210    if pending.ip.is_none() {
211        return;
212    }
213
214    if let Some(iface) = pending.iface.as_deref() {
215        if iface != name {
216            return;
217        }
218    }
219
220    let ip = pending.ip.take();
221    let netmask = pending
222        .netmask
223        .take()
224        .unwrap_or(Ipv4Address::new(255, 255, 255, 0));
225    pending.iface = None;
226    drop(pending);
227
228    if let Some(ip) = ip {
229        let _ = set_interface_ip_with_mask(name, ip, netmask);
230    }
231}