use crate::api::clock;
use crate::api::console::Style;
use crate::api::fs;
use crate::api::ini;
use crate::api::process::ExitCode;
use crate::api::syscall;
use crate::sys;
use crate::sys::console;
use crate::sys::net;
use crate::sys::net::EthernetDeviceIO;
use alloc::format;
use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec;
use core::str::FromStr;
use smoltcp::iface::SocketSet;
use smoltcp::phy::Device;
use smoltcp::socket::tcp;
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetFrame, IpCidr, Ipv4Address, PrettyPrinter};
pub fn main(args: &[&str]) -> Result<(), ExitCode> {
match *args.get(1).unwrap_or(&"") {
"-h" | "--help" => {
help();
return Ok(());
}
"c" | "config" => {
if args.len() < 3 {
print_config("mac");
print_config("ip");
print_config("gw");
print_config("dns");
} else if args[2] == "-h" || args[2] == "--help" {
help_config();
return Ok(());
} else if args.len() < 4 {
print_config(args[2]);
} else {
set_config(args[2], args[3]);
}
}
"s" | "stat" => {
stat();
}
"m" | "monitor" => {
monitor();
}
_ => {
error!("Invalid command");
return Err(ExitCode::Failure);
}
}
Ok(())
}
fn help() {
let csi_option = Style::color("aqua");
let csi_title = Style::color("yellow");
let csi_reset = Style::reset();
println!(
"{}Usage:{} net {}<command>{}",
csi_title, csi_reset, csi_option, csi_reset
);
println!();
println!("{}Commands:{}", csi_title, csi_reset);
println!(" {}config{} Configure network", csi_option, csi_reset);
println!(" {}monitor{} Monitor network", csi_option, csi_reset);
println!(
" {}stat{} Display network status",
csi_option, csi_reset
);
}
fn help_config() {
let csi_option = Style::color("aqua");
let csi_title = Style::color("yellow");
let csi_reset = Style::reset();
println!(
"{}Usage:{} net config {}<attribute> <value>{}",
csi_title, csi_reset, csi_option, csi_reset
);
println!();
println!("{}Attributes:{}", csi_title, csi_reset);
println!(" {}mac{} MAC Address", csi_option, csi_reset);
println!(" {}ip{} IP Address", csi_option, csi_reset);
println!(" {}gw{} Gateway Address", csi_option, csi_reset);
println!(" {}dns{} Domain Name Servers", csi_option, csi_reset);
}
fn print_config(attribute: &str) {
let csi_color = Style::color("aqua");
let csi_reset = Style::reset();
if let Some(value) = get_config(attribute) {
let width = 4 - attribute.len();
println!(
"{}{}:{}{:width$}{}",
csi_color,
attribute,
csi_reset,
"",
value,
width = width
);
}
}
const DNS_FILE: &str = "/ini/dns.ini";
fn dns_config() -> Option<String> {
warning!("This command is deprecated, use '{}' instead", DNS_FILE);
if let Ok(buf) = fs::read_to_string(DNS_FILE) {
if let Some(config) = ini::parse(&buf) {
if let Some(servers) = config.get("dns") {
if servers.split(',').all(|s| Ipv4Address::from_str(s).is_ok()) {
Some(servers.to_string())
} else {
error!("Could not parse '{}'", servers);
None
}
} else {
error!("Could not find 'dns' in '{}'", DNS_FILE);
None
}
} else {
error!("Could not parse '{}'", DNS_FILE);
None
}
} else {
error!("Could not read '{}'", DNS_FILE);
None
}
}
fn gw_config() -> Option<String> {
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| {
if let Some(route) = storage.iter().next() {
res = Some(route.via_router.to_string());
}
});
} else {
error!("Network error");
}
res
}
fn ip_config() -> Option<String> {
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!(
"{}/{}", ip_cidr.address(), ip_cidr.prefix_len()
));
}
} else {
error!("Network error");
}
None
}
fn mac_config() -> Option<String> {
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 {
error!("Network error");
}
None
}
pub fn get_config(attribute: &str) -> Option<String> {
match attribute {
"dns" => dns_config(),
"gw" => gw_config(),
"ip" => ip_config(),
"mac" => mac_config(),
_ => {
error!("Invalid config attribute");
None
}
}
}
pub fn set_config(attribute: &str, value: &str) {
match attribute {
"debug" => {
if let Some((_, ref mut device)) = *sys::net::NET.lock() {
match value {
"1" | "true" => device.config().enable_debug(),
"0" | "false" => device.config().disable_debug(),
_ => error!("Invalid config value"),
}
} else {
error!("Network error");
}
}
"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| {
addrs.clear();
addrs.push(addr).unwrap();
log!("NET IP {}", value);
});
} else {
error!("Network error");
}
} else {
error!("Could not parse address");
}
}
"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();
} else if let Ok(ip) = Ipv4Address::from_str(value) {
iface.routes_mut().add_default_ipv4_route(ip).unwrap();
log!("NET GW {}", value);
} else {
error!("Could not parse address");
}
} else {
error!("Network error");
}
}
"dns" => {
warning!("This command is deprecated, use '{}' instead", DNS_FILE);
let servers = value.trim();
if servers.split(',').all(|s| Ipv4Address::from_str(s).is_ok()) {
let config = format!("dns = {}\n", servers);
if fs::write(DNS_FILE, config.as_bytes()).is_ok() {
log!("NET DNS {}", servers);
} else {
error!("Could not write to '{}'", DNS_FILE);
}
} else {
error!("Could not parse '{}'", servers);
}
}
_ => {
error!("Invalid config key");
}
}
}
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");
let csi_reset = Style::reset();
println!(
"{}rx:{} {} packets ({} bytes)",
csi_color,
csi_reset,
stats.rx_packets_count(),
stats.rx_bytes_count()
);
println!(
"{}tx:{} {} packets ({} bytes)",
csi_color,
csi_reset,
stats.tx_packets_count(),
stats.tx_bytes_count()
);
} else {
error!("Network error");
}
}
fn monitor() {
if let Some((ref mut iface, ref mut device)) = *net::NET.lock() {
device.config().enable_debug();
let mtu = device.capabilities().max_transmission_unit;
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; mtu]);
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; mtu]);
let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
let mut sockets = SocketSet::new(vec![]);
let tcp_handle = sockets.add(tcp_socket);
loop {
if console::end_of_text() || console::end_of_transmission() {
println!();
return;
}
syscall::sleep(0.1);
let ms = (clock::epoch_time() * 1000000.0) as i64;
let time = Instant::from_micros(ms);
iface.poll(time, device, &mut sockets);
let socket = sockets.get_mut::<tcp::Socket>(tcp_handle);
if socket.may_recv() {
socket.recv(|buffer| {
let recvd_len = buffer.len();
let data = buffer.to_owned();
let pp = PrettyPrinter::<EthernetFrame<&[u8]>>::new(
"", &buffer
);
debug!("{}", pp);
(recvd_len, data)
}).unwrap();
}
}
} else {
error!("Network error");
}
}