mirror of https://github.com/vinc/moros.git
246 lines
8.8 KiB
Rust
246 lines
8.8 KiB
Rust
use crate::{sys, usr, debug};
|
|
use alloc::format;
|
|
use crate::api::syscall;
|
|
use crate::api::fs;
|
|
use crate::api::console::Style;
|
|
use crate::sys::net::EthernetDeviceIO;
|
|
|
|
use alloc::borrow::ToOwned;
|
|
use alloc::string::ToString;
|
|
use alloc::string::String;
|
|
use alloc::vec;
|
|
use core::str::FromStr;
|
|
use smoltcp::wire::{EthernetFrame, PrettyPrinter, IpCidr, Ipv4Address};
|
|
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
|
|
use smoltcp::time::Instant;
|
|
use smoltcp::phy::Device;
|
|
|
|
pub fn main(args: &[&str]) -> usr::shell::ExitCode {
|
|
if args.len() == 1 {
|
|
help();
|
|
return usr::shell::ExitCode::CommandError;
|
|
}
|
|
|
|
match args[1] {
|
|
"-h" | "--help" => {
|
|
return help();
|
|
}
|
|
"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" {
|
|
return help_config();
|
|
} else if args.len() < 4 {
|
|
print_config(args[2]);
|
|
} else {
|
|
set_config(args[2], args[3]);
|
|
}
|
|
}
|
|
"stat" => {
|
|
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
|
|
let stats = iface.device().stats();
|
|
let csi_color = Style::color("LightCyan");
|
|
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");
|
|
}
|
|
}
|
|
"monitor" => {
|
|
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
|
|
iface.device_mut().config().enable_debug();
|
|
|
|
let mtu = iface.device().capabilities().max_transmission_unit;
|
|
let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; mtu]);
|
|
let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; mtu]);
|
|
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
|
|
let tcp_handle = iface.add_socket(tcp_socket);
|
|
|
|
loop {
|
|
if sys::console::end_of_text() || sys::console::end_of_transmission() {
|
|
println!();
|
|
iface.remove_socket(tcp_handle);
|
|
return usr::shell::ExitCode::CommandSuccessful;
|
|
}
|
|
syscall::sleep(0.1);
|
|
|
|
let timestamp = Instant::from_micros((syscall::realtime() * 1000000.0) as i64);
|
|
if let Err(e) = iface.poll(timestamp) {
|
|
error!("Network Error: {}", e);
|
|
}
|
|
|
|
let socket = iface.get_socket::<TcpSocket>(tcp_handle);
|
|
if socket.may_recv() {
|
|
socket.recv(|buffer| {
|
|
let recvd_len = buffer.len();
|
|
let data = buffer.to_owned();
|
|
debug!("{}", PrettyPrinter::<EthernetFrame<&[u8]>>::new("", &buffer));
|
|
(recvd_len, data)
|
|
}).unwrap();
|
|
}
|
|
}
|
|
} else {
|
|
error!("Network error");
|
|
}
|
|
}
|
|
_ => {
|
|
error!("Invalid command");
|
|
return usr::shell::ExitCode::CommandError;
|
|
}
|
|
}
|
|
usr::shell::ExitCode::CommandSuccessful
|
|
}
|
|
|
|
fn help() -> usr::shell::ExitCode {
|
|
let csi_option = Style::color("LightCyan");
|
|
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);
|
|
usr::shell::ExitCode::CommandSuccessful
|
|
}
|
|
|
|
fn help_config() -> usr::shell::ExitCode {
|
|
let csi_option = Style::color("LightCyan");
|
|
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);
|
|
usr::shell::ExitCode::CommandSuccessful
|
|
}
|
|
|
|
fn print_config(attribute: &str) {
|
|
let csi_color = Style::color("LightCyan");
|
|
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";
|
|
|
|
pub fn get_config(attribute: &str) -> Option<String> {
|
|
match attribute {
|
|
"mac" => {
|
|
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
|
|
return Some(iface.hardware_addr().to_string());
|
|
} else {
|
|
error!("Network error");
|
|
}
|
|
None
|
|
}
|
|
"ip" => {
|
|
if let Some(ref mut iface) = *sys::net::IFACE.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
|
|
}
|
|
"gw" => {
|
|
let mut res = None;
|
|
if let Some(ref mut iface) = *sys::net::IFACE.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
|
|
}
|
|
"dns" => {
|
|
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()) {
|
|
Some(servers.to_string())
|
|
} else {
|
|
error!("Could not parse '{}'", servers);
|
|
None
|
|
}
|
|
} else {
|
|
error!("Could not read '{}'", DNS_FILE);
|
|
None
|
|
}
|
|
}
|
|
_ => {
|
|
error!("Invalid config attribute");
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn set_config(attribute: &str, value: &str) {
|
|
match attribute {
|
|
"debug" => {
|
|
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
|
|
match value {
|
|
"1" | "true" => iface.device_mut().config().enable_debug(),
|
|
"0" | "false" => iface.device_mut().config().disable_debug(),
|
|
_ => error!("Invalid config value"),
|
|
}
|
|
} else {
|
|
error!("Network error");
|
|
}
|
|
}
|
|
"ip" => {
|
|
if let Ok(ip) = IpCidr::from_str(value) {
|
|
if let Some(ref mut iface) = *sys::net::IFACE.lock() {
|
|
iface.update_ip_addrs(|addrs| {
|
|
if let Some(addr) = addrs.iter_mut().next() {
|
|
*addr = ip;
|
|
}
|
|
});
|
|
} else {
|
|
error!("Network error");
|
|
}
|
|
} else {
|
|
error!("Could not parse address");
|
|
}
|
|
}
|
|
"gw" => {
|
|
if let Some(ref mut iface) = *sys::net::IFACE.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();
|
|
} else {
|
|
error!("Could not parse address");
|
|
}
|
|
} else {
|
|
error!("Network error");
|
|
}
|
|
}
|
|
"dns" => {
|
|
let servers = value.trim();
|
|
if servers.split(',').all(|s| Ipv4Address::from_str(s).is_ok()) {
|
|
if fs::write(DNS_FILE, format!("{}\n", servers).as_bytes()).is_err() {
|
|
error!("Could not write to '{}'", DNS_FILE);
|
|
}
|
|
} else {
|
|
error!("Could not parse '{}'", servers);
|
|
}
|
|
}
|
|
_ => {
|
|
error!("Invalid config key");
|
|
}
|
|
}
|
|
}
|