1use 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
63pub 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
126pub 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 if crate::network::protocol_stack::get_network_manager()
136 .get_layer("ip")
137 .is_none()
138 {
139 return Err("Network stack not initialized");
142 }
143
144 if let Some(interface) = network_manager.get_interface(name) {
145 interface.set_ip_address(ip);
147
148 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 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 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 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
201fn 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}