hermit/executor/
device.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3#[cfg(not(feature = "dhcpv4"))]
4use core::str::FromStr;
5
6use smoltcp::iface::{Config, Interface, SocketSet};
7use smoltcp::phy::{self, ChecksumCapabilities, Device, DeviceCapabilities, Medium};
8#[cfg(feature = "dhcpv4")]
9use smoltcp::socket::dhcpv4;
10#[cfg(all(feature = "dns", not(feature = "dhcpv4")))]
11use smoltcp::socket::dns;
12use smoltcp::time::Instant;
13#[cfg(not(feature = "dhcpv4"))]
14use smoltcp::wire::Ipv4Address;
15use smoltcp::wire::{EthernetAddress, HardwareAddress};
16#[cfg(not(feature = "dhcpv4"))]
17use smoltcp::wire::{IpAddress, IpCidr};
18
19use super::network::{NetworkInterface, NetworkState};
20use crate::arch;
21#[cfg(not(feature = "pci"))]
22use crate::arch::kernel::mmio as hardware;
23use crate::drivers::net::NetworkDriver;
24#[cfg(feature = "pci")]
25use crate::drivers::pci as hardware;
26
27/// Data type to determine the mac address
28#[derive(Debug, Clone)]
29#[repr(C)]
30pub(crate) struct HermitNet {
31	mtu: u16,
32	checksums: ChecksumCapabilities,
33}
34
35impl HermitNet {
36	pub(crate) const fn new(mtu: u16, checksums: ChecksumCapabilities) -> Self {
37		Self { mtu, checksums }
38	}
39}
40
41impl<'a> NetworkInterface<'a> {
42	#[cfg(feature = "dhcpv4")]
43	pub(crate) fn create() -> NetworkState<'a> {
44		let (mtu, mac, checksums) = if let Some(driver) = hardware::get_network_driver() {
45			let guard = driver.lock();
46			(
47				guard.get_mtu(),
48				guard.get_mac_address(),
49				guard.get_checksums(),
50			)
51		} else {
52			return NetworkState::InitializationFailed;
53		};
54
55		let mut device = HermitNet::new(mtu, checksums.clone());
56
57		if hermit_var!("HERMIT_IP").is_some() {
58			warn!(
59				"A static IP address is specified with the environment variable HERMIT_IP, but the device is configured to use DHCPv4!"
60			);
61		}
62
63		let ethernet_addr = EthernetAddress([mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]);
64		let hardware_addr = HardwareAddress::Ethernet(ethernet_addr);
65
66		info!("MAC address {hardware_addr}");
67		info!("{checksums:?}");
68		info!("MTU: {mtu} bytes");
69
70		let dhcp = dhcpv4::Socket::new();
71
72		// use the current time based on the wall-clock time as seed
73		let mut config = Config::new(hardware_addr);
74		config.random_seed = (arch::kernel::systemtime::now_micros()) / 1_000_000;
75		if device.capabilities().medium == Medium::Ethernet {
76			config.hardware_addr = hardware_addr;
77		}
78
79		let iface = Interface::new(config, &mut device, crate::executor::network::now());
80		let mut sockets = SocketSet::new(vec![]);
81		let dhcp_handle = sockets.add(dhcp);
82
83		NetworkState::Initialized(Box::new(Self {
84			iface,
85			sockets,
86			device,
87			dhcp_handle,
88			#[cfg(feature = "dns")]
89			dns_handle: None,
90		}))
91	}
92
93	#[cfg(not(feature = "dhcpv4"))]
94	pub(crate) fn create() -> NetworkState<'a> {
95		let (mtu, mac, checksums) = if let Some(driver) = hardware::get_network_driver() {
96			let guard = driver.lock();
97			(
98				guard.get_mtu(),
99				guard.get_mac_address(),
100				guard.get_checksums(),
101			)
102		} else {
103			return NetworkState::InitializationFailed;
104		};
105
106		let mut device = HermitNet::new(mtu, checksums.clone());
107
108		let myip = Ipv4Address::from_str(hermit_var_or!("HERMIT_IP", "10.0.5.3")).unwrap();
109		let mygw = Ipv4Address::from_str(hermit_var_or!("HERMIT_GATEWAY", "10.0.5.1")).unwrap();
110		let mymask = Ipv4Address::from_str(hermit_var_or!("HERMIT_MASK", "255.255.255.0")).unwrap();
111		// Quad9 DNS server
112		#[cfg(feature = "dns")]
113		let mydns1 = Ipv4Address::from_str(hermit_var_or!("HERMIT_DNS1", "9.9.9.9")).unwrap();
114		// Cloudflare DNS server
115		#[cfg(feature = "dns")]
116		let mydns2 = Ipv4Address::from_str(hermit_var_or!("HERMIT_DNS2", "1.1.1.1")).unwrap();
117
118		// calculate the netmask length
119		// => count the number of contiguous 1 bits,
120		// starting at the most significant bit in the first octet
121		let mut prefix_len = (!mymask.octets()[0]).trailing_zeros();
122		if prefix_len == 8 {
123			prefix_len += (!mymask.octets()[1]).trailing_zeros();
124		}
125		if prefix_len == 16 {
126			prefix_len += (!mymask.octets()[2]).trailing_zeros();
127		}
128		if prefix_len == 24 {
129			prefix_len += (!mymask.octets()[3]).trailing_zeros();
130		}
131
132		let ethernet_addr = EthernetAddress([mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]);
133		let hardware_addr = HardwareAddress::Ethernet(ethernet_addr);
134		let ip_addrs = [IpCidr::new(
135			IpAddress::v4(
136				myip.octets()[0],
137				myip.octets()[1],
138				myip.octets()[2],
139				myip.octets()[3],
140			),
141			prefix_len.try_into().unwrap(),
142		)];
143
144		info!("MAC address {hardware_addr}");
145		info!("Configure network interface with address {}", ip_addrs[0]);
146		info!("Configure gateway with address {mygw}");
147		info!("{checksums:?}");
148		info!("MTU: {mtu} bytes");
149
150		// use the current time based on the wall-clock time as seed
151		let mut config = Config::new(hardware_addr);
152		config.random_seed = (arch::kernel::systemtime::now_micros()) / 1_000_000;
153		if device.capabilities().medium == Medium::Ethernet {
154			config.hardware_addr = hardware_addr;
155		}
156
157		let mut iface = Interface::new(config, &mut device, crate::executor::network::now());
158		iface.update_ip_addrs(|ip_addrs| {
159			ip_addrs
160				.push(IpCidr::new(
161					IpAddress::v4(
162						myip.octets()[0],
163						myip.octets()[1],
164						myip.octets()[2],
165						myip.octets()[3],
166					),
167					prefix_len.try_into().unwrap(),
168				))
169				.unwrap();
170		});
171		iface.routes_mut().add_default_ipv4_route(mygw).unwrap();
172
173		#[allow(unused_mut)]
174		let mut sockets = SocketSet::new(vec![]);
175
176		#[cfg(feature = "dns")]
177		let dns_handle = {
178			let servers = &[mydns1.into(), mydns2.into()];
179			let dns_socket = dns::Socket::new(servers, vec![]);
180			sockets.add(dns_socket)
181		};
182
183		NetworkState::Initialized(Box::new(Self {
184			iface,
185			sockets,
186			device,
187			#[cfg(feature = "dns")]
188			dns_handle: Some(dns_handle),
189		}))
190	}
191}
192
193impl Device for HermitNet {
194	type RxToken<'a> = RxToken;
195	type TxToken<'a> = TxToken;
196
197	fn capabilities(&self) -> DeviceCapabilities {
198		let mut cap = DeviceCapabilities::default();
199		cap.max_transmission_unit = self.mtu.into();
200		cap.max_burst_size = Some(0x10000 / cap.max_transmission_unit);
201		cap.checksum = self.checksums.clone();
202		cap
203	}
204
205	fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
206		if let Some(driver) = hardware::get_network_driver() {
207			driver.lock().receive_packet()
208		} else {
209			None
210		}
211	}
212
213	fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
214		Some(TxToken::new())
215	}
216}
217
218// Unique handle to identify the RxToken
219pub(crate) type RxHandle = usize;
220
221#[doc(hidden)]
222pub(crate) struct RxToken {
223	buffer: Vec<u8>,
224}
225
226impl RxToken {
227	pub(crate) fn new(buffer: Vec<u8>) -> Self {
228		Self { buffer }
229	}
230}
231
232impl phy::RxToken for RxToken {
233	fn consume<R, F>(self, f: F) -> R
234	where
235		F: FnOnce(&[u8]) -> R,
236	{
237		f(&self.buffer[..])
238	}
239}
240
241#[doc(hidden)]
242pub(crate) struct TxToken;
243
244impl TxToken {
245	pub(crate) fn new() -> Self {
246		Self {}
247	}
248}
249
250impl phy::TxToken for TxToken {
251	fn consume<R, F>(self, len: usize, f: F) -> R
252	where
253		F: FnOnce(&mut [u8]) -> R,
254	{
255		hardware::get_network_driver()
256			.unwrap()
257			.lock()
258			.send_packet(len, f)
259	}
260}