redox/schemes/ethernetd/src/scheme.rs

176 lines
5.6 KiB
Rust
Raw Normal View History

2016-10-23 23:26:36 +02:00
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{self, Read};
use std::os::unix::io::AsRawFd;
use std::{cmp, str, u16};
2016-10-23 23:26:36 +02:00
use netutils::{getcfg, n16, MacAddr, EthernetII, EthernetIIHeader};
use syscall;
2016-10-23 23:26:36 +02:00
use syscall::error::{Error, Result, EACCES, EBADF, ENOENT, EINVAL, EWOULDBLOCK};
use syscall::scheme::SchemeMut;
2016-10-23 23:26:36 +02:00
#[derive(Clone)]
pub struct Handle {
/// The Host's MAC address
pub host_addr: MacAddr,
/// The Peer's MAC address
pub peer_addr: Option<MacAddr>,
2016-10-23 23:26:36 +02:00
/// The ethernet type
pub ethertype: u16,
/// The data
pub frames: VecDeque<EthernetII>,
}
pub struct EthernetScheme {
network: File,
next_id: usize,
pub handles: BTreeMap<usize, Handle>
}
impl EthernetScheme {
pub fn new(network: File) -> EthernetScheme {
EthernetScheme {
network: network,
next_id: 1,
handles: BTreeMap::new(),
}
}
2016-10-23 23:26:36 +02:00
//TODO: Minimize allocation
//TODO: Reduce iteration cost (use BTreeMap of ethertype to handle?)
pub fn input(&mut self) -> io::Result<usize> {
let mut bytes = [0; 65536];
let count = self.network.read(&mut bytes)?;
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
for (_id, handle) in self.handles.iter_mut() {
if frame.header.ethertype.get() == handle.ethertype {
if handle.peer_addr.is_none() {
handle.peer_addr = Some(frame.header.src);
}
2016-10-23 23:26:36 +02:00
handle.frames.push_back(frame.clone());
}
}
Ok(count)
} else {
Ok(0)
}
}
}
2016-10-23 23:26:36 +02:00
impl SchemeMut for EthernetScheme {
fn open(&mut self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
2016-10-23 23:26:36 +02:00
let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?);
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
let mut parts = path.split("/");
if let Some(host_string) = parts.next() {
if let Some(ethertype_string) = parts.next() {
let ethertype = u16::from_str_radix(ethertype_string, 16).unwrap_or(0);
let peer_addr = if ! host_string.is_empty() {
Some(MacAddr::from_str(host_string))
} else {
None
};
let next_id = self.next_id;
self.next_id += 1;
self.handles.insert(next_id, Handle {
host_addr: mac_addr,
peer_addr: peer_addr,
ethertype: ethertype,
frames: VecDeque::new()
});
return Ok(next_id);
} else {
println!("Ethernet: No ethertype provided");
}
} else {
println!("Ethernet: No host provided");
}
Err(Error::new(ENOENT))
} else {
Err(Error::new(EACCES))
}
}
2016-10-23 23:26:36 +02:00
fn dup(&mut self, id: usize) -> Result<usize> {
let next_id = self.next_id;
self.next_id += 1;
let handle = {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
handle.clone()
};
self.handles.insert(next_id, handle);
Ok(next_id)
}
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
if let Some(frame) = handle.frames.pop_front() {
for (b, d) in buf.iter_mut().zip(frame.data.iter()) {
*b = *d;
}
Ok(cmp::min(buf.len(), frame.data.len()))
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
match syscall::write(self.network.as_raw_fd(), &EthernetII {
header: EthernetIIHeader {
src: handle.host_addr,
dst: handle.peer_addr.unwrap_or(MacAddr::BROADCAST),
2016-10-23 23:26:36 +02:00
ethertype: n16::new(handle.ethertype),
},
data: Vec::from(buf),
}
.to_bytes()) {
Ok(_) => Ok(buf.len()),
Err(err) => Err(err),
}
}
fn fevent(&mut self, id: usize, _flags: usize) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
Ok(id)
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_string = format!("ethernet:{}/{:X}", handle.peer_addr.map_or(String::new(), |mac| mac.to_string()), handle.ethertype);
2016-10-23 23:26:36 +02:00
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
}
Ok(cmp::min(buf.len(), path.len()))
}
fn fsync(&mut self, id: usize) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
syscall::fsync(self.network.as_raw_fd())
}
fn close(&mut self, id: usize) -> Result<usize> {
let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
drop(handle);
Ok(0)
}
}