Files
RedBear-OS/src/smolnetd/device.rs
T
Jeremy Soller 01f30577c1 Update smoltcp
2019-11-29 18:54:09 -07:00

124 lines
3.2 KiB
Rust

use smoltcp;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::fs::File;
use std::io::Write;
use std::rc::Rc;
use smoltcp::time::Instant;
use smoltcp::wire::EthernetAddress;
use buffer_pool::{Buffer, BufferPool};
struct NetworkDeviceData {
network_file: Rc<RefCell<File>>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
local_hwaddr: smoltcp::wire::EthernetAddress,
buffer_pool: Rc<RefCell<BufferPool>>,
}
pub struct NetworkDevice {
data: Rc<RefCell<NetworkDeviceData>>,
}
impl NetworkDevice {
pub const MTU: usize = 1520;
pub fn new(
network_file: Rc<RefCell<File>>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
local_hwaddr: smoltcp::wire::EthernetAddress,
buffer_pool: Rc<RefCell<BufferPool>>,
) -> NetworkDevice {
NetworkDevice {
data: Rc::new(RefCell::new(NetworkDeviceData {
network_file,
input_queue,
local_hwaddr,
buffer_pool,
})),
}
}
}
pub struct RxToken {
buffer: Buffer,
}
impl smoltcp::phy::RxToken for RxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> smoltcp::Result<R>
where
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
{
f(&mut self.buffer)
}
}
pub struct TxToken {
data: Rc<RefCell<NetworkDeviceData>>,
}
impl smoltcp::phy::TxToken for TxToken {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result<R>
where
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
{
let data = self.data.borrow_mut();
let mut buffer = data.buffer_pool.borrow_mut().get_buffer();
buffer.resize(len);
let res = f(&mut buffer)?;
let mut loopback = false;
if let Ok(mut frame) = smoltcp::wire::EthernetFrame::new_checked(&mut buffer) {
if frame.dst_addr() == EthernetAddress::default() {
frame.set_dst_addr(data.local_hwaddr);
loopback = true;
}
}
if loopback {
data.input_queue.borrow_mut().push_back(buffer.move_out());
} else {
data.network_file
.borrow_mut()
.write(&buffer)
.map_err(|_| smoltcp::Error::Dropped)?;
}
Ok(res)
}
}
impl<'a> smoltcp::phy::Device<'a> for NetworkDevice {
type RxToken = RxToken;
type TxToken = TxToken;
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
let mut limits = smoltcp::phy::DeviceCapabilities::default();
limits.max_transmission_unit = Self::MTU;
limits.max_burst_size = Some(20);
limits
}
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
let data = self.data.borrow_mut();
let buffer = data.input_queue.borrow_mut().pop_front();
if let Some(buffer) = buffer {
Some((
RxToken { buffer },
TxToken {
data: Rc::clone(&self.data),
},
))
} else {
None
}
}
fn transmit(&'a mut self) -> Option<Self::TxToken> {
Some(TxToken {
data: Rc::clone(&self.data),
})
}
}