milestone: desktop path Phases 1-5

Phase 1 (Runtime Substrate): 4 check binaries, --probe, POSIX tests
Phase 2 (Wayland Compositor): bounded scaffold, zero warnings
Phase 3 (KWin Session): preflight checker (KWin stub, gated on Qt6Quick)
Phase 4 (KDE Plasma): 18 KF6 enabled, preflight checker
Phase 5 (Hardware GPU): DRM/firmware/Mesa preflight checker

Build: zero warnings, all scripts syntax-clean. Oracle-verified.
This commit is contained in:
2026-04-29 09:54:06 +01:00
parent b23714f542
commit 8acc73d774
508 changed files with 76526 additions and 396 deletions
@@ -0,0 +1,190 @@
use std::cell::RefCell;
use std::rc::Rc;
use smoltcp::phy::{Device, DeviceCapabilities, Medium};
use smoltcp::storage::PacketMetadata;
use smoltcp::time::Instant;
use smoltcp::wire::IpAddress;
use self::route_table::RouteTable;
use crate::link::DeviceList;
use crate::scheme::Smolnetd;
pub mod route_table;
pub type PacketBuffer = smoltcp::storage::PacketBuffer<'static, ()>;
pub struct Router {
rx_buffer: PacketBuffer,
tx_buffer: PacketBuffer,
devices: Rc<RefCell<DeviceList>>,
route_table: Rc<RefCell<RouteTable>>,
}
impl Router {
pub fn new(devices: Rc<RefCell<DeviceList>>, route_table: Rc<RefCell<RouteTable>>) -> Self {
let rx_buffer = PacketBuffer::new(
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0u8; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE],
);
let tx_buffer = PacketBuffer::new(
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0u8; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE],
);
Self {
rx_buffer,
tx_buffer,
devices,
route_table,
}
}
pub const MTU: usize = 1486;
pub fn can_recv(&self) -> bool {
let mut can_recv = false;
for dev in self.devices.borrow().iter() {
can_recv |= dev.can_recv();
}
can_recv
}
pub fn poll(&mut self, now: Instant) {
for dev in self.devices.borrow_mut().iter_mut() {
if self.rx_buffer.is_full() {
break;
}
loop {
if self.rx_buffer.is_full() {
break;
}
let Some(buf) = dev.recv(now) else {
break;
};
self.rx_buffer
.enqueue(buf.len(), ())
.expect("We checked if it was full")
.copy_from_slice(buf);
}
}
}
pub fn dispatch(&mut self, now: Instant) {
while let Ok(((), packet)) = self.tx_buffer.dequeue() {
if let Ok(mut packet) = smoltcp::wire::Ipv4Packet::new_checked(packet) {
let dst_addr = IpAddress::Ipv4(packet.dst_addr());
if packet.dst_addr().is_broadcast() {
let buf = packet.into_inner();
for dev in self.devices.borrow_mut().iter_mut() {
dev.send(dst_addr, buf, now)
}
} else {
let route_table = self.route_table.borrow();
let Some(rule) = route_table.lookup_rule(&dst_addr) else {
warn!("No route found for destination: {}", dst_addr);
continue;
};
let next_hop = match rule.via {
Some(via) => via,
None => dst_addr,
};
let mut devices = self.devices.borrow_mut();
let Some(dev) = devices.get_mut(&rule.dev) else {
warn!("Device {} not found", rule.dev);
// TODO: Remove route if device doesn't exist anymore ?
continue;
};
let IpAddress::Ipv4(src) = rule.src;
if src != packet.src_addr() {
packet.set_src_addr(src);
packet.fill_checksum()
}
dev.send(next_hop, packet.into_inner(), now);
}
}
}
}
}
impl Device for Router {
type RxToken<'a> = RxToken<'a>;
type TxToken<'a> = TxToken<'a>;
fn receive(
&mut self,
_timestamp: smoltcp::time::Instant,
) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
if self.rx_buffer.is_empty() || self.tx_buffer.is_full() {
None
} else {
Some((
RxToken {
rx_buffer: &mut self.rx_buffer,
},
TxToken {
tx_buffer: &mut self.tx_buffer,
},
))
}
}
fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
if self.tx_buffer.is_full() {
None
} else {
Some(TxToken {
tx_buffer: &mut self.tx_buffer,
})
}
}
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.medium = Medium::Ip;
caps.max_transmission_unit = Router::MTU;
caps.max_burst_size = Some(Smolnetd::SOCKET_BUFFER_SIZE);
caps
}
}
pub struct TxToken<'a> {
tx_buffer: &'a mut PacketBuffer,
}
impl smoltcp::phy::TxToken for TxToken<'_> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
f(self
.tx_buffer
.enqueue(len, ())
.expect("This was checked before creating the TxToken"))
}
}
pub struct RxToken<'a> {
rx_buffer: &'a mut PacketBuffer,
}
impl<'a> smoltcp::phy::RxToken for RxToken<'a> {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
let ((), buf) = self
.rx_buffer
.dequeue()
.expect("This was checked before creating the RxToken");
f(buf)
}
}
@@ -0,0 +1,99 @@
use std::fmt::Display;
use std::rc::Rc;
use smoltcp::wire::{IpAddress, IpCidr};
#[derive(Debug)]
pub struct Rule {
pub filter: IpCidr,
pub via: Option<IpAddress>,
pub dev: Rc<str>,
pub src: IpAddress,
}
impl Rule {
pub fn new(filter: IpCidr, via: Option<IpAddress>, dev: Rc<str>, src: IpAddress) -> Self {
Self {
filter,
via,
dev,
src,
}
}
}
impl Display for Rule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.filter.prefix_len() == 0 {
write!(f, "default")?;
} else {
write!(f, "{} ", self.filter)?;
}
if let Some(via) = self.via {
write!(f, " via {}", via)?;
}
write!(f, " dev {}", self.dev)?;
write!(f, " src {}", self.src)?;
Ok(())
}
}
#[derive(Debug, Default)]
pub struct RouteTable {
rules: Vec<Rule>,
}
impl RouteTable {
pub fn lookup_rule(&self, dst: &IpAddress) -> Option<&Rule> {
self.rules
.iter()
.rev()
.find(|rule| rule.filter.contains_addr(dst))
}
pub fn lookup_src_addr(&self, dst: &IpAddress) -> Option<IpAddress> {
Some(self.lookup_rule(dst)?.src)
}
pub fn lookup_gateway(&self, dst: &IpAddress) -> Option<IpAddress> {
self.lookup_rule(dst)?.via
}
pub fn lookup_device(&self, dst: &IpAddress) -> Option<Rc<str>> {
Some(self.lookup_rule(dst)?.dev.clone())
}
pub fn insert_rule(&mut self, new_rule: Rule) {
let i = match self
.rules
.binary_search_by_key(&new_rule.filter.prefix_len(), |rule| {
rule.filter.prefix_len()
}) {
Ok(i) | Err(i) => i,
};
self.rules.insert(i, new_rule);
}
pub fn remove_rule(&mut self, filter: IpCidr) {
self.rules.retain(|rule| rule.filter != filter);
}
pub fn change_src(&mut self, old_src: IpAddress, new_src: IpAddress) {
for rule in self.rules.iter_mut().filter(|rule| rule.src == old_src) {
rule.src = new_src;
}
}
}
impl Display for RouteTable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for rule in self.rules.iter() {
writeln!(f, "{}", rule)?;
}
Ok(())
}
}