diff --git a/src/smolnetd/scheme/mod.rs b/src/smolnetd/scheme/mod.rs index 9a0d4742ab..e03eed4b7b 100644 --- a/src/smolnetd/scheme/mod.rs +++ b/src/smolnetd/scheme/mod.rs @@ -71,7 +71,7 @@ impl Smolnetd { .expect("Can't parse the 'mac' cfg"); let local_ip = IpAddress::from_str(getcfg("ip").unwrap().trim()).expect("Can't parse the 'ip' cfg."); - let protocol_addrs = [ + let protocol_addrs = vec![ IpCidr::new(local_ip, 24), IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8), ]; diff --git a/src/smolnetd/scheme/netcfg.rs b/src/smolnetd/scheme/netcfg.rs index 7bf9049657..d629431fac 100644 --- a/src/smolnetd/scheme/netcfg.rs +++ b/src/smolnetd/scheme/netcfg.rs @@ -1,3 +1,4 @@ +// use managed::ManagedSlice; use std::cell::RefCell; use std::collections::BTreeMap; use std::fs::File; @@ -5,8 +6,7 @@ use std::io::{Read, Write}; use std::str; use std::str::FromStr; use std::rc::Rc; -use std::iter::FromIterator; -use smoltcp::wire::{EthernetAddress, Ipv4Address}; +use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address}; use syscall::data::Stat; use syscall::flag::{MODE_DIR, MODE_FILE}; use syscall::{Error as SyscallError, Packet as SyscallPacket, Result as SyscallResult, SchemeMut}; @@ -32,11 +32,11 @@ trait CfgNode { true } - fn read(&self) -> Vec { - vec![] + fn read(&self) -> String { + String::new() } - fn write(&self, _buf: &[u8]) -> SyscallResult { + fn write(&self, _buf: &str) -> SyscallResult { Ok(0) } @@ -47,23 +47,23 @@ trait CfgNode { struct RONode where - F: Fn() -> Vec, + F: Fn() -> String, { read_fun: F, } impl CfgNode for RONode where - F: Fn() -> Vec, + F: Fn() -> String, { - fn read(&self) -> Vec { + fn read(&self) -> String { (self.read_fun)() } } impl RONode where - F: 'static + Fn() -> Vec, + F: 'static + Fn() -> String, { fn new(read_fun: F) -> CfgNodeRef { Rc::new(RefCell::new(RONode { read_fun })) @@ -72,16 +72,16 @@ where struct WONode where - F: Fn(&[u8]) -> SyscallResult, + F: Fn(&str) -> SyscallResult, { write_fun: F, } impl CfgNode for WONode where - F: Fn(&[u8]) -> SyscallResult, + F: Fn(&str) -> SyscallResult, { - fn write(&self, buf: &[u8]) -> SyscallResult { + fn write(&self, buf: &str) -> SyscallResult { (self.write_fun)(buf) } @@ -92,7 +92,7 @@ where impl WONode where - F: 'static + Fn(&[u8]) -> SyscallResult, + F: 'static + Fn(&str) -> SyscallResult, { fn new(write_fun: F) -> CfgNodeRef { Rc::new(RefCell::new(WONode { write_fun })) @@ -101,8 +101,8 @@ where struct RWNode where - F: Fn() -> Vec, - G: Fn(&[u8]) -> SyscallResult, + F: Fn() -> String, + G: Fn(&str) -> SyscallResult, { read_fun: F, write_fun: G, @@ -110,14 +110,14 @@ where impl CfgNode for RWNode where - F: Fn() -> Vec, - G: Fn(&[u8]) -> SyscallResult, + F: Fn() -> String, + G: Fn(&str) -> SyscallResult, { - fn read(&self) -> Vec { + fn read(&self) -> String { (self.read_fun)() } - fn write(&self, buf: &[u8]) -> SyscallResult { + fn write(&self, buf: &str) -> SyscallResult { (self.write_fun)(buf) } @@ -128,8 +128,8 @@ where impl RWNode where - F: 'static + Fn() -> Vec, - G: 'static + Fn(&[u8]) -> SyscallResult, + F: 'static + Fn() -> String, + G: 'static + Fn(&str) -> SyscallResult, { fn new(read_fun: F, write_fun: G) -> CfgNodeRef { Rc::new(RefCell::new(RWNode { @@ -148,13 +148,13 @@ impl CfgNode for StaticDirNode { true } - fn read(&self) -> Vec { - let mut files = vec![]; + fn read(&self) -> String { + let mut files = String::new(); for child in self.child_nodes.keys() { if !files.is_empty() { - files.push(b'\n'); + files.push('\n'); } - files.extend(child.bytes()); + files += child; } files } @@ -170,8 +170,45 @@ impl StaticDirNode { } } -fn parse_default_gw(buf: &[u8]) -> SyscallResult { - let value = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?; +macro_rules! cfg_node { + (val $e:expr) => { + $e + }; + (ro [ $($c:ident)* ] || $b:block ) => { + { + $(let $c = $c.clone();)* + RONode::new(move|| $b) + } + }; + (wo [ $($c:ident)* ] |$i:ident| $b:block ) => { + { + $(let $c = $c.clone();)* + WONode::new(move |$i: &str| $b) + } + }; + (rw [ $($c:ident)* ] || $rb:block |$i:ident| $wb:block ) => { + { + let read_fun = { + $(let $c = $c.clone();)* + move || $rb + }; + let write_fun = { + $(let $c = $c.clone();)* + move |$i: &str| $wb + }; + RWNode::new(read_fun, write_fun) + } + }; + ($($e:expr => { $($t:tt)* }),* $(,)*) => { + { + let mut children = BTreeMap::new(); + $(children.insert($e.into(), cfg_node!($($t)*));)* + StaticDirNode::new(children) + } + }; +} + +fn parse_default_gw(value: &str) -> SyscallResult { let mut routes = value.lines(); if let Some(route) = routes.next() { if !routes.next().is_none() { @@ -190,71 +227,110 @@ fn parse_default_gw(buf: &[u8]) -> SyscallResult { Err(SyscallError::new(syscall::EINVAL)) } -fn mk_route_node(iface: &Interface) -> CfgNodeRef { - let iface_ = Rc::clone(iface); - let route_list_node = RONode::new(move || { - let default_route = if let Some(ip) = iface_.borrow().ipv4_gateway() { - format!("default via {}\n", ip) - } else { - String::new() - }; - Vec::from_iter(default_route.bytes()) - }); - let iface_ = Rc::clone(iface); - let route_add_node = WONode::new(move |buf: &[u8]| -> SyscallResult { - let default_gw = parse_default_gw(buf)?; - iface_.borrow_mut().set_ipv4_gateway(Some(default_gw)); - Ok(0) - }); - let iface_ = Rc::clone(iface); - let route_rm_node = WONode::new(move |buf: &[u8]| -> SyscallResult { - let default_gw = parse_default_gw(buf)?; - let mut iface = iface_.borrow_mut(); - if iface.ipv4_gateway() != Some(default_gw) { - return Err(SyscallError::new(syscall::EINVAL)); - } - iface.set_ipv4_gateway(None); - Ok(0) - }); - let mut route_child_nodes = BTreeMap::new(); - route_child_nodes.insert("list".to_owned(), route_list_node); - route_child_nodes.insert("add".to_owned(), route_add_node); - route_child_nodes.insert("rm".to_owned(), route_rm_node); - StaticDirNode::new(route_child_nodes) -} - -fn mk_iface_node(iface: &Interface) -> CfgNodeRef { - let iface_ = Rc::clone(iface); - let iface__ = Rc::clone(iface); - let iface_mac_node = RWNode::new( - move || Vec::from_iter(format!("{}\n", iface_.borrow().ethernet_addr()).bytes()), - move |buf: &[u8]| -> SyscallResult { - let value = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?; - let mac = - EthernetAddress::from_str(value).map_err(|_| SyscallError::new(syscall::EINVAL))?; - if !mac.is_unicast() { - return Err(SyscallError::new(syscall::EINVAL)); - } - iface__.borrow_mut().set_ethernet_addr(mac); - Ok(0) - }, - ); - let mut iface_child_nodes = BTreeMap::new(); - iface_child_nodes.insert("mac".to_owned(), iface_mac_node); - StaticDirNode::new(iface_child_nodes) -} - fn mk_root_node(iface: Interface) -> CfgNodeRef { - let route_node = mk_route_node(&iface); - let mut ifaces_nodes = BTreeMap::new(); - - ifaces_nodes.insert("eth0".to_owned(), mk_iface_node(&iface)); - let ifaces_node = StaticDirNode::new(ifaces_nodes); - - let mut root_child_nodes = BTreeMap::new(); - root_child_nodes.insert("route".to_owned(), route_node); - root_child_nodes.insert("ifaces".to_owned(), ifaces_node); - StaticDirNode::new(root_child_nodes) + cfg_node!{ + "route" => { + "list" => { + ro [iface] || { + if let Some(ip) = iface.borrow().ipv4_gateway() { + format!("default via {}\n", ip) + } else { + String::new() + } + } + }, + "add" => { + wo [iface] |routes| { + let default_gw = parse_default_gw(routes)?; + iface.borrow_mut().set_ipv4_gateway(Some(default_gw)); + Ok(0) + } + }, + "rm" => { + wo [iface] |routes| { + let default_gw = parse_default_gw(routes)?; + let mut iface = iface.borrow_mut(); + if iface.ipv4_gateway() != Some(default_gw) { + return Err(SyscallError::new(syscall::EINVAL)); + } + iface.set_ipv4_gateway(None); + Ok(0) + } + } + }, + "ifaces" => { + "eth0" => { + "mac" => { + rw [iface] + || { + format!("{}\n", iface.borrow().ethernet_addr()) + } + |mac| { + let mac = mac.lines().next() + .ok_or_else(|| SyscallError::new(syscall::EINVAL))?; + let mac = EthernetAddress::from_str(mac). + map_err(|_| SyscallError::new(syscall::EINVAL))?; + if !mac.is_unicast() { + return Err(SyscallError::new(syscall::EINVAL)); + } + iface.borrow_mut().set_ethernet_addr(mac); + Ok(0) + } + }, + "addr" => { + "list" => { + ro [iface] || { + let mut ips = String::new(); + for cidr in iface.borrow().ip_addrs() { + ips += &format!("{}\n", cidr); + } + ips + } + }, + "add" => { + wo [iface] |input| { + let mut iface = iface.borrow_mut(); + let mut cidrs = iface.ip_addrs().iter().cloned().collect::>(); + for cidr in input.lines() { + let cidr = IpCidr::from_str(cidr) + .map_err(|_| SyscallError::new(syscall::EINVAL))?; + if !cidr.address().is_unicast() { + return Err(SyscallError::new(syscall::EINVAL)); + } + cidrs.insert(0, cidr); + } + iface.update_ip_addrs(|s| { + *s = From::from(cidrs); + }); + Ok(0) + } + }, + "rm" => { + wo [iface] |input| { + let mut iface = iface.borrow_mut(); + let mut cidrs = iface.ip_addrs().iter().cloned().collect::>(); + for cidr in input.lines() { + let cidr = IpCidr::from_str(cidr) + .map_err(|_| SyscallError::new(syscall::EINVAL))?; + if !cidr.address().is_unicast() { + return Err(SyscallError::new(syscall::EINVAL)); + } + let pre_retain_len = cidrs.len(); + cidrs.retain(|&c| c != cidr); + if pre_retain_len == cidrs.len() { + return Err(SyscallError::new(syscall::EINVAL)); + } + } + iface.update_ip_addrs(|s| { + *s = From::from(cidrs); + }); + Ok(0) + } + }, + } + } + } + } } struct NetCfgFile { @@ -309,7 +385,7 @@ impl SchemeMut for NetCfgScheme { .ok_or_else(|| SyscallError::new(syscall::EINVAL))?; current_node = next_node; } - let read_buf = current_node.borrow().read(); + let read_buf = Vec::from(current_node.borrow().read()); let fd = self.next_fd; self.next_fd += 1; self.files.insert( @@ -329,7 +405,9 @@ impl SchemeMut for NetCfgScheme { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; - file.cfg_node.borrow().write(&file.write_buf) + let value = + str::from_utf8(&file.write_buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?; + file.cfg_node.borrow().write(&value) } fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult {