From 1e9580824252aae98d1c09985cbadf6bba873b33 Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Thu, 11 Jan 2018 00:57:18 +0300 Subject: [PATCH] netcfg write nodes --- src/smolnetd/scheme/icmp.rs | 6 +- src/smolnetd/scheme/mod.rs | 8 +- src/smolnetd/scheme/netcfg.rs | 262 +++++++++++++++++++++++----------- src/smolnetd/scheme/socket.rs | 11 +- 4 files changed, 193 insertions(+), 94 deletions(-) diff --git a/src/smolnetd/scheme/icmp.rs b/src/smolnetd/scheme/icmp.rs index bccb75a3b0..cacb9f6605 100644 --- a/src/smolnetd/scheme/icmp.rs +++ b/src/smolnetd/scheme/icmp.rs @@ -92,8 +92,10 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> { tx_packets.push(IcmpPacketBuffer::new(vec![0; NetworkDevice::MTU])); } - let socket = IcmpSocket::new(IcmpSocketBuffer::new(rx_packets), - IcmpSocketBuffer::new(tx_packets)); + let socket = IcmpSocket::new( + IcmpSocketBuffer::new(rx_packets), + IcmpSocketBuffer::new(tx_packets), + ); let handle = socket_set.add(socket); let mut icmp_socket = socket_set.get::(handle); let ident = ident_set diff --git a/src/smolnetd/scheme/mod.rs b/src/smolnetd/scheme/mod.rs index 611e41810d..9a0d4742ab 100644 --- a/src/smolnetd/scheme/mod.rs +++ b/src/smolnetd/scheme/mod.rs @@ -187,15 +187,15 @@ impl Smolnetd { Err(smoltcp::Error::Unrecognized) => (), Err(e) => { error!("poll error: {}", e); - break 0 + break 0; } } match iface.poll_at(&socket_set, timestamp) { Some(n) if n > timestamp => { break ::std::cmp::min(::std::i64::MAX as u64, n - timestamp) as i64 - }, - Some(_) => {}, - None => break ::std::i64::MAX + } + Some(_) => {} + None => break ::std::i64::MAX, } } }; diff --git a/src/smolnetd/scheme/netcfg.rs b/src/smolnetd/scheme/netcfg.rs index 8e4833fec1..7bf9049657 100644 --- a/src/smolnetd/scheme/netcfg.rs +++ b/src/smolnetd/scheme/netcfg.rs @@ -3,8 +3,10 @@ use std::collections::BTreeMap; use std::fs::File; 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 syscall::data::Stat; use syscall::flag::{MODE_DIR, MODE_FILE}; use syscall::{Error as SyscallError, Packet as SyscallPacket, Result as SyscallResult, SchemeMut}; @@ -13,6 +15,8 @@ use syscall; use error::Result; use super::Interface; +const WRITE_BUFFER_MAX_SIZE: usize = 0xffff; + type CfgNodeRef = Rc>; trait CfgNode { @@ -32,15 +36,13 @@ trait CfgNode { vec![] } - fn write(&mut self, _buf: &[u8]) -> Option { - None + fn write(&self, _buf: &[u8]) -> SyscallResult { + Ok(0) } fn open(&self, _file: &str) -> Option { None } - - fn close(&mut self) {} } struct RONode @@ -68,6 +70,75 @@ where } } +struct WONode +where + F: Fn(&[u8]) -> SyscallResult, +{ + write_fun: F, +} + +impl CfgNode for WONode +where + F: Fn(&[u8]) -> SyscallResult, +{ + fn write(&self, buf: &[u8]) -> SyscallResult { + (self.write_fun)(buf) + } + + fn is_writable(&self) -> bool { + true + } +} + +impl WONode +where + F: 'static + Fn(&[u8]) -> SyscallResult, +{ + fn new(write_fun: F) -> CfgNodeRef { + Rc::new(RefCell::new(WONode { write_fun })) + } +} + +struct RWNode +where + F: Fn() -> Vec, + G: Fn(&[u8]) -> SyscallResult, +{ + read_fun: F, + write_fun: G, +} + +impl CfgNode for RWNode +where + F: Fn() -> Vec, + G: Fn(&[u8]) -> SyscallResult, +{ + fn read(&self) -> Vec { + (self.read_fun)() + } + + fn write(&self, buf: &[u8]) -> SyscallResult { + (self.write_fun)(buf) + } + + fn is_writable(&self) -> bool { + true + } +} + +impl RWNode +where + F: 'static + Fn() -> Vec, + G: 'static + Fn(&[u8]) -> SyscallResult, +{ + fn new(read_fun: F, write_fun: G) -> CfgNodeRef { + Rc::new(RefCell::new(RWNode { + read_fun, + write_fun, + })) + } +} + struct StaticDirNode { child_nodes: BTreeMap, } @@ -99,60 +170,97 @@ impl StaticDirNode { } } -struct RootNode { - route_node: CfgNodeRef, - iface_nodes: BTreeMap, +fn parse_default_gw(buf: &[u8]) -> SyscallResult { + let value = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?; + let mut routes = value.lines(); + if let Some(route) = routes.next() { + if !routes.next().is_none() { + return Err(SyscallError::new(syscall::EINVAL)); + } + let mut words = route.split_whitespace(); + if let Some("default") = words.next() { + if let Some("via") = words.next() { + if let Some(ip) = words.next() { + return Ipv4Address::from_str(ip) + .map_err(|_| SyscallError::new(syscall::EINVAL)); + } + } + } + } + Err(SyscallError::new(syscall::EINVAL)) } -impl RootNode { - pub fn new(iface: Interface) -> RootNode { - 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 mut route_child_nodes = BTreeMap::new(); - route_child_nodes.insert("list".to_owned(), route_list_node); - let route_node = StaticDirNode::new(route_child_nodes); - let iface_nodes = BTreeMap::new(); - // let eth0_node: CfgNodeRef = Rc::new(RefCell::new(IfaceNode::new(iface))); - // iface_nodes.insert("eth0".to_owned(), eth0_node); - RootNode { - route_node, - iface_nodes, +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) } -impl CfgNode for RootNode { - fn is_dir(&self) -> bool { - true - } +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 open(&self, file: &str) -> Option { - match file { - "route" => Some(Rc::clone(&self.route_node)), - _ => self.iface_nodes.get(file).map(|node| Rc::clone(node)), - } - } +fn mk_root_node(iface: Interface) -> CfgNodeRef { + let route_node = mk_route_node(&iface); + let mut ifaces_nodes = BTreeMap::new(); - fn read(&self) -> Vec { - let mut files = vec![]; - files.extend_from_slice(b"route"); - for iface in self.iface_nodes.keys() { - files.push(b'\n'); - files.extend(iface.bytes()); - } - files - } + 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) } struct NetCfgFile { cfg_node: CfgNodeRef, - data: Option>, + read_buf: Vec, + write_buf: Vec, pos: usize, uid: u32, } @@ -170,7 +278,7 @@ impl NetCfgScheme { scheme_file, next_fd: 1, files: BTreeMap::new(), - root_node: Rc::new(RefCell::new(RootNode::new(iface))), + root_node: mk_root_node(iface), } } @@ -201,6 +309,7 @@ impl SchemeMut for NetCfgScheme { .ok_or_else(|| SyscallError::new(syscall::EINVAL))?; current_node = next_node; } + let read_buf = current_node.borrow().read(); let fd = self.next_fd; self.next_fd += 1; self.files.insert( @@ -209,53 +318,48 @@ impl SchemeMut for NetCfgScheme { cfg_node: current_node, uid, pos: 0, - data: None, + read_buf, + write_buf: vec![], }, ); Ok(fd) } fn close(&mut self, fd: usize) -> SyscallResult { - self.files - .get(&fd) - .ok_or_else(|| SyscallError::new(syscall::EBADF))? - .cfg_node - .borrow_mut() - .close(); - self.files.remove(&fd); - Ok(0) + let file = self.files + .get_mut(&fd) + .ok_or_else(|| SyscallError::new(syscall::EBADF))?; + file.cfg_node.borrow().write(&file.write_buf) } fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult { let file = self.files - .get(&fd) + .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; + if file.uid != 0 { return Err(SyscallError::new(syscall::EACCES)); } - file.cfg_node - .borrow_mut() - .write(buf) - .ok_or_else(|| SyscallError::new(syscall::EINVAL)) + + if (WRITE_BUFFER_MAX_SIZE - file.write_buf.len()) < buf.len() { + return Err(SyscallError::new(syscall::EMSGSIZE)); + } + file.write_buf.extend_from_slice(buf); + Ok(buf.len()) } fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; - if file.data.is_none() { - file.data = Some(file.cfg_node.borrow().read()) + + let mut i = 0; + while i < buf.len() && file.pos < file.read_buf.len() { + buf[i] = file.read_buf[file.pos]; + i += 1; + file.pos += 1; } - if let Some(ref data) = file.data { - let mut i = 0; - while i < buf.len() && file.pos < data.len() { - buf[i] = data[file.pos]; - i += 1; - file.pos += 1; - } - return Ok(i); - } - Err(SyscallError::new(syscall::EINVAL)) + Ok(i) } fn fstat(&mut self, fd: usize, stat: &mut Stat) -> SyscallResult { @@ -277,15 +381,7 @@ impl SchemeMut for NetCfgScheme { } stat.st_uid = 0; stat.st_gid = 0; - - if file.data.is_none() { - file.data = Some(file.cfg_node.borrow().read()) - } - if let Some(ref data) = file.data { - stat.st_size = data.len() as u64; - } else { - stat.st_size = 0; - } + stat.st_size = file.read_buf.len() as u64; Ok(0) } diff --git a/src/smolnetd/scheme/socket.rs b/src/smolnetd/scheme/socket.rs index a94f16ac24..d6723964ab 100644 --- a/src/smolnetd/scheme/socket.rs +++ b/src/smolnetd/scheme/socket.rs @@ -84,8 +84,8 @@ where { pub fn socket_handle(&self) -> SocketHandle { match *self { - SchemeFile::Socket(SocketFile { socket_handle, .. }) | - SchemeFile::Setting(SettingFile { socket_handle, .. }) => socket_handle, + SchemeFile::Socket(SocketFile { socket_handle, .. }) + | SchemeFile::Setting(SettingFile { socket_handle, .. }) => socket_handle, } } } @@ -580,9 +580,10 @@ where } fn dup(&mut self, fd: usize, buf: &[u8]) -> SyscallResult { - if let Some((flags, uid, gid)) = self.nulls.get(&fd).map(|null| { - (null.flags, null.uid, null.gid) - }) { + if let Some((flags, uid, gid)) = self.nulls + .get(&fd) + .map(|null| (null.flags, null.uid, null.gid)) + { return self.open(buf, flags, uid, gid); }