netcfg write nodes
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user