hermit/executor/
network.rs

1use alloc::boxed::Box;
2#[cfg(feature = "dns")]
3use alloc::vec::Vec;
4use core::future;
5use core::sync::atomic::{AtomicU16, Ordering};
6use core::task::Poll;
7
8use hermit_sync::InterruptTicketMutex;
9use smoltcp::iface::{PollResult, SocketHandle, SocketSet};
10use smoltcp::socket::AnySocket;
11#[cfg(feature = "dhcpv4")]
12use smoltcp::socket::dhcpv4;
13#[cfg(feature = "dns")]
14use smoltcp::socket::dns::{self, GetQueryResultError, QueryHandle};
15#[cfg(feature = "tcp")]
16use smoltcp::socket::tcp;
17#[cfg(feature = "udp")]
18use smoltcp::socket::udp;
19use smoltcp::time::{Duration, Instant};
20#[cfg(feature = "dns")]
21use smoltcp::wire::{DnsQueryType, IpAddress};
22#[cfg(feature = "dhcpv4")]
23use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr};
24
25use crate::arch;
26use crate::executor::device::HermitNet;
27use crate::executor::spawn;
28#[cfg(feature = "dns")]
29use crate::io;
30use crate::scheduler::PerCoreSchedulerExt;
31
32pub(crate) enum NetworkState<'a> {
33	Missing,
34	InitializationFailed,
35	Initialized(Box<NetworkInterface<'a>>),
36}
37
38impl<'a> NetworkState<'a> {
39	pub fn as_nic_mut(&mut self) -> Result<&mut NetworkInterface<'a>, &'static str> {
40		match self {
41			NetworkState::Initialized(nic) => Ok(nic),
42			_ => Err("Network is not initialized!"),
43		}
44	}
45}
46
47pub(crate) type Handle = SocketHandle;
48
49static LOCAL_ENDPOINT: AtomicU16 = AtomicU16::new(0);
50pub(crate) static NIC: InterruptTicketMutex<NetworkState<'_>> =
51	InterruptTicketMutex::new(NetworkState::Missing);
52
53pub(crate) struct NetworkInterface<'a> {
54	pub(super) iface: smoltcp::iface::Interface,
55	pub(super) sockets: SocketSet<'a>,
56	pub(super) device: HermitNet,
57	#[cfg(feature = "dhcpv4")]
58	pub(super) dhcp_handle: SocketHandle,
59	#[cfg(feature = "dns")]
60	pub(super) dns_handle: Option<SocketHandle>,
61}
62
63#[cfg(target_arch = "x86_64")]
64fn start_endpoint() -> u16 {
65	((unsafe { core::arch::x86_64::_rdtsc() }) % u64::from(u16::MAX))
66		.try_into()
67		.unwrap()
68}
69
70#[cfg(target_arch = "aarch64")]
71fn start_endpoint() -> u16 {
72	use core::arch::asm;
73	let value: u64;
74
75	unsafe {
76		asm!(
77			"mrs {value}, cntpct_el0",
78			value = out(reg) value,
79			options(nostack),
80		);
81	}
82
83	(value % u64::from(u16::MAX)).try_into().unwrap()
84}
85
86#[cfg(target_arch = "riscv64")]
87fn start_endpoint() -> u16 {
88	(riscv::register::time::read64() % u64::from(u16::MAX))
89		.try_into()
90		.unwrap()
91}
92
93#[inline]
94pub(crate) fn now() -> Instant {
95	Instant::from_micros_const(arch::kernel::systemtime::now_micros().try_into().unwrap())
96}
97
98#[cfg(feature = "dhcpv4")]
99async fn dhcpv4_run() {
100	let dhcp_handle = NIC.lock().as_nic_mut().unwrap().dhcp_handle;
101
102	future::poll_fn(|cx| {
103		let mut guard = NIC.lock();
104		let nic = guard.as_nic_mut().unwrap();
105		let socket = nic.sockets.get_mut::<dhcpv4::Socket<'_>>(dhcp_handle);
106
107		socket.register_waker(cx.waker());
108
109		match socket.poll() {
110			None => {}
111			Some(dhcpv4::Event::Configured(config)) => {
112				info!("DHCP config acquired!");
113				info!("IP address:      {}", config.address);
114				nic.iface.update_ip_addrs(|addrs| {
115					if let Some(dest) = addrs.iter_mut().next() {
116						*dest = IpCidr::Ipv4(config.address);
117					} else if addrs.push(IpCidr::Ipv4(config.address)).is_err() {
118						info!("Unable to update IP address");
119					}
120				});
121				if let Some(router) = config.router {
122					info!("Default gateway: {router}");
123					nic.iface
124						.routes_mut()
125						.add_default_ipv4_route(router)
126						.unwrap();
127				} else {
128					info!("Default gateway: None");
129					nic.iface.routes_mut().remove_default_ipv4_route();
130				}
131
132				#[cfg(feature = "dns")]
133				let mut dns_servers: Vec<IpAddress> = Vec::new();
134				for (i, s) in config.dns_servers.iter().enumerate() {
135					info!("DNS server {i}:    {s}");
136					#[cfg(feature = "dns")]
137					dns_servers.push(IpAddress::Ipv4(*s));
138				}
139
140				#[cfg(feature = "dns")]
141				if !dns_servers.is_empty() {
142					let dns_socket = dns::Socket::new(dns_servers.as_slice(), vec![]);
143					nic.dns_handle = Some(nic.sockets.add(dns_socket));
144				}
145			}
146			Some(dhcpv4::Event::Deconfigured) => {
147				info!("DHCP lost config!");
148				let cidr = Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0);
149				nic.iface.update_ip_addrs(|addrs| {
150					if let Some(dest) = addrs.iter_mut().next() {
151						*dest = IpCidr::Ipv4(cidr);
152					}
153				});
154				nic.iface.routes_mut().remove_default_ipv4_route();
155
156				#[cfg(feature = "dns")]
157				{
158					if let Some(dns_handle) = nic.dns_handle {
159						nic.sockets.remove(dns_handle);
160					}
161
162					nic.dns_handle = None;
163				}
164			}
165		};
166
167		Poll::<()>::Pending
168	})
169	.await;
170}
171
172async fn network_run() {
173	future::poll_fn(|_cx| {
174		if let Some(mut guard) = NIC.try_lock() {
175			match &mut *guard {
176				NetworkState::Initialized(nic) => {
177					nic.poll_common(now());
178					Poll::Pending
179				}
180				_ => Poll::Ready(()),
181			}
182		} else {
183			// another task is already using the NIC => don't check
184			Poll::Pending
185		}
186	})
187	.await;
188}
189
190#[cfg(feature = "dns")]
191pub(crate) async fn get_query_result(query: QueryHandle) -> io::Result<Vec<IpAddress>> {
192	future::poll_fn(|cx| {
193		let mut guard = NIC.lock();
194		let nic = guard.as_nic_mut().unwrap();
195		let socket = nic.get_mut_dns_socket()?;
196		match socket.get_query_result(query) {
197			Ok(addrs) => {
198				let mut ips = Vec::new();
199				for x in &addrs {
200					ips.push(*x);
201				}
202
203				Poll::Ready(Ok(ips))
204			}
205			Err(GetQueryResultError::Pending) => {
206				socket.register_query_waker(query, cx.waker());
207				Poll::Pending
208			}
209			Err(e) => {
210				warn!("DNS query failed: {e:?}");
211				Poll::Ready(Err(io::Error::ENOENT))
212			}
213		}
214	})
215	.await
216}
217
218pub(crate) fn init() {
219	info!("Try to initialize network!");
220
221	// initialize variable, which contains the next local endpoint
222	LOCAL_ENDPOINT.store(start_endpoint(), Ordering::Relaxed);
223
224	let mut guard = NIC.lock();
225
226	*guard = NetworkInterface::create();
227
228	if let NetworkState::Initialized(nic) = &mut *guard {
229		let time = now();
230		nic.poll_common(time);
231		let wakeup_time = nic
232			.poll_delay(time)
233			.map(|d| crate::arch::processor::get_timer_ticks() + d.total_micros());
234		crate::core_scheduler().add_network_timer(wakeup_time);
235
236		spawn(network_run());
237		#[cfg(feature = "dhcpv4")]
238		spawn(dhcpv4_run());
239	}
240}
241
242impl<'a> NetworkInterface<'a> {
243	#[cfg(feature = "udp")]
244	pub(crate) fn create_udp_handle(&mut self) -> Result<Handle, ()> {
245		let udp_rx_buffer =
246			udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 4], vec![0; 0x10000]);
247		let udp_tx_buffer =
248			udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY; 4], vec![0; 0x10000]);
249		let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
250		let udp_handle = self.sockets.add(udp_socket);
251
252		Ok(udp_handle)
253	}
254
255	#[cfg(feature = "tcp")]
256	pub(crate) fn create_tcp_handle(&mut self) -> Result<Handle, ()> {
257		let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 0x10000]);
258		let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 0x10000]);
259		let mut tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
260		tcp_socket.set_nagle_enabled(true);
261		let tcp_handle = self.sockets.add(tcp_socket);
262
263		Ok(tcp_handle)
264	}
265
266	pub(crate) fn poll_common(&mut self, timestamp: Instant) -> PollResult {
267		self.iface
268			.poll(timestamp, &mut self.device, &mut self.sockets)
269	}
270
271	pub(crate) fn poll_delay(&mut self, timestamp: Instant) -> Option<Duration> {
272		self.iface.poll_delay(timestamp, &self.sockets)
273	}
274
275	#[allow(dead_code)]
276	pub(crate) fn get_socket<T: AnySocket<'a>>(&self, handle: SocketHandle) -> &T {
277		self.sockets.get(handle)
278	}
279
280	pub(crate) fn get_mut_socket<T: AnySocket<'a>>(&mut self, handle: SocketHandle) -> &mut T {
281		self.sockets.get_mut(handle)
282	}
283
284	pub(crate) fn get_socket_and_context<T: AnySocket<'a>>(
285		&mut self,
286		handle: SocketHandle,
287	) -> (&mut T, &mut smoltcp::iface::Context) {
288		(self.sockets.get_mut(handle), self.iface.context())
289	}
290
291	pub(crate) fn destroy_socket(&mut self, handle: Handle) {
292		// This deallocates the socket's buffers
293		self.sockets.remove(handle);
294	}
295
296	#[cfg(feature = "dns")]
297	pub(crate) fn start_query(
298		&mut self,
299		name: &str,
300		query_type: DnsQueryType,
301	) -> io::Result<QueryHandle> {
302		let dns_handle = self.dns_handle.ok_or(io::Error::EINVAL)?;
303		let socket: &mut dns::Socket<'a> = self.sockets.get_mut(dns_handle);
304		socket
305			.start_query(self.iface.context(), name, query_type)
306			.map_err(|_| io::Error::EIO)
307	}
308
309	#[allow(dead_code)]
310	#[cfg(feature = "dns")]
311	pub(crate) fn get_dns_socket(&self) -> io::Result<&dns::Socket<'a>> {
312		let dns_handle = self.dns_handle.ok_or(io::Error::EINVAL)?;
313		Ok(self.sockets.get(dns_handle))
314	}
315
316	#[cfg(feature = "dns")]
317	pub(crate) fn get_mut_dns_socket(&mut self) -> io::Result<&mut dns::Socket<'a>> {
318		let dns_handle = self.dns_handle.ok_or(io::Error::EINVAL)?;
319		Ok(self.sockets.get_mut(dns_handle))
320	}
321}