netcfg write nodes

This commit is contained in:
Egor Karavaev
2018-01-11 00:57:18 +03:00
parent a7f365d96c
commit 1e95808242
4 changed files with 193 additions and 94 deletions
+4 -2
View File
@@ -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::<IcmpSocket>(handle);
let ident = ident_set
+4 -4
View File
@@ -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,
}
}
};
+179 -83
View File
@@ -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<RefCell<CfgNode>>;
trait CfgNode {
@@ -32,15 +36,13 @@ trait CfgNode {
vec![]
}
fn write(&mut self, _buf: &[u8]) -> Option<usize> {
None
fn write(&self, _buf: &[u8]) -> SyscallResult<usize> {
Ok(0)
}
fn open(&self, _file: &str) -> Option<CfgNodeRef> {
None
}
fn close(&mut self) {}
}
struct RONode<F>
@@ -68,6 +70,75 @@ where
}
}
struct WONode<F>
where
F: Fn(&[u8]) -> SyscallResult<usize>,
{
write_fun: F,
}
impl<F> CfgNode for WONode<F>
where
F: Fn(&[u8]) -> SyscallResult<usize>,
{
fn write(&self, buf: &[u8]) -> SyscallResult<usize> {
(self.write_fun)(buf)
}
fn is_writable(&self) -> bool {
true
}
}
impl<F> WONode<F>
where
F: 'static + Fn(&[u8]) -> SyscallResult<usize>,
{
fn new(write_fun: F) -> CfgNodeRef {
Rc::new(RefCell::new(WONode { write_fun }))
}
}
struct RWNode<F, G>
where
F: Fn() -> Vec<u8>,
G: Fn(&[u8]) -> SyscallResult<usize>,
{
read_fun: F,
write_fun: G,
}
impl<F, G> CfgNode for RWNode<F, G>
where
F: Fn() -> Vec<u8>,
G: Fn(&[u8]) -> SyscallResult<usize>,
{
fn read(&self) -> Vec<u8> {
(self.read_fun)()
}
fn write(&self, buf: &[u8]) -> SyscallResult<usize> {
(self.write_fun)(buf)
}
fn is_writable(&self) -> bool {
true
}
}
impl<F, G> RWNode<F, G>
where
F: 'static + Fn() -> Vec<u8>,
G: 'static + Fn(&[u8]) -> SyscallResult<usize>,
{
fn new(read_fun: F, write_fun: G) -> CfgNodeRef {
Rc::new(RefCell::new(RWNode {
read_fun,
write_fun,
}))
}
}
struct StaticDirNode {
child_nodes: BTreeMap<String, CfgNodeRef>,
}
@@ -99,60 +170,97 @@ impl StaticDirNode {
}
}
struct RootNode {
route_node: CfgNodeRef,
iface_nodes: BTreeMap<String, CfgNodeRef>,
fn parse_default_gw(buf: &[u8]) -> SyscallResult<Ipv4Address> {
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<usize> {
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<usize> {
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<usize> {
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<CfgNodeRef> {
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<u8> {
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<Vec<u8>>,
read_buf: Vec<u8>,
write_buf: Vec<u8>,
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<usize> {
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<usize> {
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<usize> {
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<usize> {
@@ -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)
}
+6 -5
View File
@@ -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<usize> {
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);
}