From 92055d5c70fd368e45531d082cf599f7e10d944a Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 8 Nov 2024 10:45:17 +0100 Subject: [PATCH] Add network config devices (#700) * Add net-gw device * Add net-ip device * Add net-mac device * Add net-usage device * Use filesystem instead of net command * Add deprecation warnings --- src/api/fs.rs | 8 ++++-- src/sys/fs/device.rs | 42 ++++++++++++++++++++++++++++- src/sys/net/gw.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/sys/net/ip.rs | 59 +++++++++++++++++++++++++++++++++++++++++ src/sys/net/mac.rs | 42 +++++++++++++++++++++++++++++ src/sys/net/mod.rs | 4 +++ src/sys/net/usage.rs | 50 +++++++++++++++++++++++++++++++++++ src/usr/dhcp.rs | 21 ++++++++------- src/usr/host.rs | 5 ++-- src/usr/install.rs | 8 ++++-- src/usr/net.rs | 8 ++++++ 11 files changed, 293 insertions(+), 17 deletions(-) create mode 100644 src/sys/net/gw.rs create mode 100644 src/sys/net/ip.rs create mode 100644 src/sys/net/mac.rs create mode 100644 src/sys/net/usage.rs diff --git a/src/api/fs.rs b/src/api/fs.rs index e67e3fe1..b4ee6f78 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -164,8 +164,12 @@ fn device_type(name: &str) -> Result { "clk-boot" => Ok(DeviceType::BootTime), "clk-epoch" => Ok(DeviceType::EpochTime), "clk-rtc" => Ok(DeviceType::RTC), - "tcp" => Ok(DeviceType::TcpSocket), - "udp" => Ok(DeviceType::UdpSocket), + "net-tcp" => Ok(DeviceType::TcpSocket), + "net-udp" => Ok(DeviceType::UdpSocket), + "net-gw" => Ok(DeviceType::NetGw), + "net-ip" => Ok(DeviceType::NetIp), + "net-mac" => Ok(DeviceType::NetMac), + "net-usage" => Ok(DeviceType::NetUsage), "vga-buffer" => Ok(DeviceType::VgaBuffer), "vga-font" => Ok(DeviceType::VgaFont), "vga-mode" => Ok(DeviceType::VgaMode), diff --git a/src/sys/fs/device.rs b/src/sys/fs/device.rs index 876eeeab..9de46a81 100644 --- a/src/sys/fs/device.rs +++ b/src/sys/fs/device.rs @@ -6,6 +6,10 @@ use super::{dirname, filename, realpath, FileIO, IO}; use crate::sys::ata::Drive; use crate::sys::clk::{RTC, EpochTime, BootTime}; use crate::sys::console::Console; +use crate::sys::net::gw::NetGw; +use crate::sys::net::ip::NetIp; +use crate::sys::net::mac::NetMac; +use crate::sys::net::usage::NetUsage; use crate::sys::net::socket::tcp::TcpSocket; use crate::sys::net::socket::udp::UdpSocket; use crate::sys::rng::Random; @@ -35,6 +39,10 @@ pub enum DeviceType { VgaMode = 12, VgaPalette = 13, Speaker = 14, + NetGw = 15, + NetIp = 16, + NetMac = 17, + NetUsage = 18, } impl TryFrom<&[u8]> for DeviceType { @@ -57,6 +65,10 @@ impl TryFrom<&[u8]> for DeviceType { 12 => Ok(DeviceType::VgaMode), 13 => Ok(DeviceType::VgaPalette), 14 => Ok(DeviceType::Speaker), + 15 => Ok(DeviceType::NetGw), + 16 => Ok(DeviceType::NetIp), + 17 => Ok(DeviceType::NetMac), + 18 => Ok(DeviceType::NetUsage), _ => Err(()), } } @@ -78,6 +90,10 @@ impl DeviceType { DeviceType::VgaBuffer => VgaBuffer::size(), DeviceType::VgaMode => VgaMode::size(), DeviceType::VgaPalette => VgaPalette::size(), + DeviceType::NetGw => NetGw::size(), + DeviceType::NetIp => NetIp::size(), + DeviceType::NetMac => NetMac::size(), + DeviceType::NetUsage => NetUsage::size(), _ => 1, }; let mut res = vec![0; len]; @@ -97,12 +113,16 @@ pub enum Device { RTC(RTC), TcpSocket(TcpSocket), UdpSocket(UdpSocket), + Drive(Drive), VgaBuffer(VgaBuffer), VgaFont(VgaFont), VgaMode(VgaMode), VgaPalette(VgaPalette), Speaker(Speaker), - Drive(Drive), + NetGw(NetGw), + NetIp(NetIp), + NetMac(NetMac), + NetUsage(NetUsage), } impl TryFrom<&[u8]> for Device { @@ -124,6 +144,10 @@ impl TryFrom<&[u8]> for Device { DeviceType::VgaMode => Ok(Device::VgaMode(VgaMode::new())), DeviceType::VgaPalette => Ok(Device::VgaPalette(VgaPalette::new())), DeviceType::Speaker => Ok(Device::Speaker(Speaker::new())), + DeviceType::NetGw => Ok(Device::NetGw(NetGw::new())), + DeviceType::NetIp => Ok(Device::NetIp(NetIp::new())), + DeviceType::NetMac => Ok(Device::NetMac(NetMac::new())), + DeviceType::NetUsage => Ok(Device::NetUsage(NetUsage::new())), DeviceType::Drive if buf.len() > 2 => { let bus = buf[1]; let dsk = buf[2]; @@ -188,6 +212,10 @@ impl FileIO for Device { Device::VgaPalette(io) => io.read(buf), Device::Speaker(io) => io.read(buf), Device::Drive(io) => io.read(buf), + Device::NetGw(io) => io.read(buf), + Device::NetIp(io) => io.read(buf), + Device::NetMac(io) => io.read(buf), + Device::NetUsage(io) => io.read(buf), } } @@ -208,6 +236,10 @@ impl FileIO for Device { Device::VgaPalette(io) => io.write(buf), Device::Speaker(io) => io.write(buf), Device::Drive(io) => io.write(buf), + Device::NetGw(io) => io.write(buf), + Device::NetIp(io) => io.write(buf), + Device::NetMac(io) => io.write(buf), + Device::NetUsage(io) => io.write(buf), } } @@ -228,6 +260,10 @@ impl FileIO for Device { Device::VgaPalette(io) => io.close(), Device::Speaker(io) => io.close(), Device::Drive(io) => io.close(), + Device::NetGw(io) => io.close(), + Device::NetIp(io) => io.close(), + Device::NetMac(io) => io.close(), + Device::NetUsage(io) => io.close(), } } @@ -248,6 +284,10 @@ impl FileIO for Device { Device::VgaPalette(io) => io.poll(event), Device::Speaker(io) => io.poll(event), Device::Drive(io) => io.poll(event), + Device::NetGw(io) => io.poll(event), + Device::NetIp(io) => io.poll(event), + Device::NetMac(io) => io.poll(event), + Device::NetUsage(io) => io.poll(event), } } } diff --git a/src/sys/net/gw.rs b/src/sys/net/gw.rs new file mode 100644 index 00000000..87cc1fb7 --- /dev/null +++ b/src/sys/net/gw.rs @@ -0,0 +1,63 @@ +use crate::api::fs::{FileIO, IO}; + +use alloc::string::{String, ToString}; +use core::str::FromStr; +use smoltcp::wire::Ipv4Address; + +#[derive(Debug, Clone)] +pub struct NetGw; + +impl NetGw { + pub fn new() -> Self { + Self + } + + pub fn size() -> usize { + 16 + } +} + +impl FileIO for NetGw { + fn read(&mut self, buf: &mut [u8]) -> Result { + if let Some((ref mut iface, _)) = *super::NET.lock() { + let mut n = 0; + iface.routes_mut().update(|storage| { + if let Some(route) = storage.iter().next() { + let s = route.via_router.to_string(); + n = s.len(); + buf[0..n].copy_from_slice(s.as_bytes()); + } + }); + if n > 0 { + return Ok(n); + } + } + Err(()) + } + + fn write(&mut self, buf: &[u8]) -> Result { + if let Some((ref mut iface, _)) = *super::NET.lock() { + if let Ok(s) = String::from_utf8(buf.to_vec()) { + if s == "0.0.0.0" { + iface.routes_mut().remove_default_ipv4_route(); + return Ok(s.len()); + } else if let Ok(ip) = Ipv4Address::from_str(&s) { + iface.routes_mut().add_default_ipv4_route(ip).unwrap(); + log!("NET GW {}", s); + return Ok(s.len()); + } + } + } + Err(()) + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => true, + } + } +} + diff --git a/src/sys/net/ip.rs b/src/sys/net/ip.rs new file mode 100644 index 00000000..8813dd43 --- /dev/null +++ b/src/sys/net/ip.rs @@ -0,0 +1,59 @@ +use crate::api::fs::{FileIO, IO}; + +use alloc::format; +use alloc::string::String; +use core::str::FromStr; +use smoltcp::wire::IpCidr; + +#[derive(Debug, Clone)] +pub struct NetIp; + +impl NetIp { + pub fn new() -> Self { + Self + } + + pub fn size() -> usize { + 16 + 1 + 3 + } +} + +impl FileIO for NetIp { + fn read(&mut self, buf: &mut [u8]) -> Result { + if let Some((ref mut iface, _)) = *super::NET.lock() { + if let Some(ip) = iface.ip_addrs().iter().next() { + let s = format!("{}/{}", ip.address(), ip.prefix_len()); + let n = s.len(); + buf[0..n].copy_from_slice(s.as_bytes()); + return Ok(n); + } + } + Err(()) + } + + fn write(&mut self, buf: &[u8]) -> Result { + if let Ok(s) = String::from_utf8(buf.to_vec()) { + if let Ok(addr) = IpCidr::from_str(&s) { + if let Some((ref mut iface, _)) = *super::NET.lock() { + iface.update_ip_addrs(|addrs| { + addrs.clear(); + addrs.push(addr).unwrap(); + log!("NET IP {}", s); + }); + return Ok(buf.len()); + } + } + } + Err(()) + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => true, + } + } +} + diff --git a/src/sys/net/mac.rs b/src/sys/net/mac.rs new file mode 100644 index 00000000..454bc23e --- /dev/null +++ b/src/sys/net/mac.rs @@ -0,0 +1,42 @@ +use crate::api::fs::{FileIO, IO}; + +use alloc::string::ToString; + +#[derive(Debug, Clone)] +pub struct NetMac; + +impl NetMac { + pub fn new() -> Self { + Self + } + + pub fn size() -> usize { + 17 + } +} + +impl FileIO for NetMac { + fn read(&mut self, buf: &mut [u8]) -> Result { + if let Some((ref mut iface, _)) = *super::NET.lock() { + let s = iface.hardware_addr().to_string(); + let n = s.len(); + buf[0..n].copy_from_slice(s.as_bytes()); + return Ok(n); + } + Err(()) + } + + fn write(&mut self, _buf: &[u8]) -> Result { + Err(()) + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } +} + diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index e4a26e75..00cc6854 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -1,4 +1,8 @@ mod nic; +pub mod gw; +pub mod ip; +pub mod mac; +pub mod usage; pub mod socket; use crate::{sys, usr}; diff --git a/src/sys/net/usage.rs b/src/sys/net/usage.rs new file mode 100644 index 00000000..6480429d --- /dev/null +++ b/src/sys/net/usage.rs @@ -0,0 +1,50 @@ +use crate::api::fs::{FileIO, IO}; +use crate::sys::net::EthernetDeviceIO; + +use alloc::format; + +#[derive(Debug, Clone)] +pub struct NetUsage; + +impl NetUsage { + pub fn new() -> Self { + Self + } + + pub fn size() -> usize { + 83 + } +} + +impl FileIO for NetUsage { + fn read(&mut self, buf: &mut [u8]) -> Result { + if let Some((_, ref mut device)) = *super::NET.lock() { + let stats = device.stats(); + let s = format!( + "{} {} {} {}", + stats.rx_packets_count(), + stats.rx_bytes_count(), + stats.tx_packets_count(), + stats.tx_bytes_count(), + ); + let n = s.len(); + buf[0..n].copy_from_slice(s.as_bytes()); + return Ok(n); + } + Err(()) + } + + fn write(&mut self, _buf: &[u8]) -> Result { + Err(()) + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } +} + diff --git a/src/usr/dhcp.rs b/src/usr/dhcp.rs index 3c90a4f8..28e79be1 100644 --- a/src/usr/dhcp.rs +++ b/src/usr/dhcp.rs @@ -1,10 +1,10 @@ use crate::api::clock; use crate::api::console::Style; +use crate::api::fs; use crate::api::process::ExitCode; use crate::api::syscall; use crate::sys::console; use crate::sys::net; -use crate::usr::shell; use alloc::format; use alloc::string::ToString; @@ -74,21 +74,22 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { return Err(ExitCode::Failure); } - if let Some((address, router, dns_servers)) = dhcp_config { - shell::exec(&format!("net config ip {}", address)).ok(); + if let Some((ip, gw, dns)) = dhcp_config { + fs::write("/dev/net/ip", ip.to_string().as_bytes()).ok(); - if let Some(router) = router { - shell::exec(&format!("net config gw {}", router)).ok(); + if let Some(gw) = gw { + fs::write("/dev/net/gw", gw.to_string().as_bytes()).ok(); } else { - shell::exec("net config gw 0.0.0.0").ok(); + fs::write("/dev/net/gw", b"0.0.0.0").ok(); } - let dns: Vec<_> = dns_servers.iter().map(|s| s.to_string()).collect(); + let dns: Vec<_> = dns.iter().map(|s| s.to_string()).collect(); if !dns.is_empty() { - shell::exec(&format!("net config dns {}", dns.join(","))).ok(); + let servers = dns.join(","); + if fs::write("/ini/dns", servers.as_bytes()).is_ok() { + log!("NET DNS {}", servers); + } } - - return Ok(()); } Err(ExitCode::Failure) diff --git a/src/usr/host.rs b/src/usr/host.rs index 60a42ef6..0588213e 100644 --- a/src/usr/host.rs +++ b/src/usr/host.rs @@ -1,9 +1,10 @@ use crate::api::console::Style; +use crate::api::fs; use crate::api::process::ExitCode; use crate::api::rng; use crate::api::syscall; use crate::sys::fs::OpenFlag; -use crate::usr; + use alloc::vec; use alloc::vec::Vec; use bit_field::BitField; @@ -117,7 +118,7 @@ impl Message { } fn dns_address() -> Option { - if let Some(servers) = usr::net::get_config("dns") { + if let Ok(servers) = fs::read_to_string("/ini/dns") { if let Some((server, _)) = servers.split_once(',') { if let Ok(addr) = IpAddress::from_str(server) { return Some(addr); diff --git a/src/usr/install.rs b/src/usr/install.rs index 30d60f32..e60f62f8 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -58,8 +58,12 @@ pub fn copy_files(verbose: bool) { create_dev("/dev/clk/epoch", "clk-epoch", verbose); create_dev("/dev/clk/rtc", "clk-rtc", verbose); create_dev("/dev/console", "console", verbose); - create_dev("/dev/net/tcp", "tcp", verbose); - create_dev("/dev/net/udp", "udp", verbose); + create_dev("/dev/net/tcp", "net-tcp", verbose); + create_dev("/dev/net/udp", "net-udp", verbose); + create_dev("/dev/net/gw", "net-gw", verbose); + create_dev("/dev/net/ip", "net-ip", verbose); + create_dev("/dev/net/mac", "net-mac", verbose); + create_dev("/dev/net/usage", "net-usage", verbose); create_dev("/dev/null", "null", verbose); create_dev("/dev/random", "random", verbose); create_dev("/dev/speaker", "speaker", verbose); diff --git a/src/usr/net.rs b/src/usr/net.rs index 2a91542d..601ad142 100644 --- a/src/usr/net.rs +++ b/src/usr/net.rs @@ -109,6 +109,7 @@ fn print_config(attribute: &str) { const DNS_FILE: &str = "/ini/dns"; fn dns_config() -> Option { + warning!("This command is deprecated, use /dev/net/dns instead"); if let Ok(value) = fs::read_to_string(DNS_FILE) { let servers = value.trim(); if servers.split(',').all(|s| Ipv4Address::from_str(s).is_ok()) { @@ -124,6 +125,7 @@ fn dns_config() -> Option { } fn gw_config() -> Option { + warning!("This command is deprecated, use /dev/net/gw instead"); let mut res = None; if let Some((ref mut iface, _)) = *sys::net::NET.lock() { iface.routes_mut().update(|storage| { @@ -138,6 +140,7 @@ fn gw_config() -> Option { } fn ip_config() -> Option { + warning!("This command is deprecated, use /dev/net/ip instead"); if let Some((ref mut iface, _)) = *sys::net::NET.lock() { if let Some(ip_cidr) = iface.ip_addrs().iter().next() { return Some(format!( @@ -151,6 +154,7 @@ fn ip_config() -> Option { } fn mac_config() -> Option { + warning!("This command is deprecated, use /dev/net/mac instead"); if let Some((ref mut iface, _)) = *sys::net::NET.lock() { return Some(iface.hardware_addr().to_string()); } else { @@ -186,6 +190,7 @@ pub fn set_config(attribute: &str, value: &str) { } } "ip" => { + warning!("This command is deprecated, use /dev/net/ip instead"); if let Ok(addr) = IpCidr::from_str(value) { if let Some((ref mut iface, _)) = *sys::net::NET.lock() { iface.update_ip_addrs(|addrs| { @@ -201,6 +206,7 @@ pub fn set_config(attribute: &str, value: &str) { } } "gw" => { + warning!("This command is deprecated, use /dev/net/gw instead"); if let Some((ref mut iface, _)) = *sys::net::NET.lock() { if value == "0.0.0.0" { iface.routes_mut().remove_default_ipv4_route(); @@ -215,6 +221,7 @@ pub fn set_config(attribute: &str, value: &str) { } } "dns" => { + warning!("This command is deprecated, use /ini/dns instead"); let servers = value.trim(); if servers.split(',').all(|s| Ipv4Address::from_str(s).is_ok()) { let s = format!("{}\n", servers); @@ -234,6 +241,7 @@ pub fn set_config(attribute: &str, value: &str) { } pub fn stat() { + warning!("This command is deprecated, use /dev/net/usage instead"); if let Some((_, ref mut device)) = *sys::net::NET.lock() { let stats = device.stats(); let csi_color = Style::color("aqua");