mirror of https://github.com/ospab/ostp.git
110 lines
2.9 KiB
Rust
110 lines
2.9 KiB
Rust
use std::sync::{
|
|
atomic::{AtomicBool, Ordering},
|
|
Arc,
|
|
};
|
|
|
|
use smoltcp::{
|
|
phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken},
|
|
time::Instant,
|
|
};
|
|
use tokio::sync::mpsc::{unbounded_channel, Permit, Sender, UnboundedReceiver, UnboundedSender};
|
|
|
|
use crate::packet::AnyIpPktFrame;
|
|
|
|
pub(super) struct VirtualDevice {
|
|
in_buf_avail: Arc<AtomicBool>,
|
|
in_buf: UnboundedReceiver<Vec<u8>>,
|
|
out_buf: Sender<AnyIpPktFrame>,
|
|
mtu: usize,
|
|
cached_packet: Option<Vec<u8>>,
|
|
}
|
|
|
|
impl VirtualDevice {
|
|
pub(super) fn new(
|
|
iface_egress_tx: Sender<AnyIpPktFrame>,
|
|
mtu: usize,
|
|
) -> (Self, UnboundedSender<Vec<u8>>, Arc<AtomicBool>) {
|
|
let iface_ingress_tx_avail = Arc::new(AtomicBool::new(false));
|
|
let (iface_ingress_tx, iface_ingress_rx) = unbounded_channel();
|
|
(
|
|
Self {
|
|
in_buf_avail: iface_ingress_tx_avail.clone(),
|
|
in_buf: iface_ingress_rx,
|
|
out_buf: iface_egress_tx,
|
|
mtu,
|
|
cached_packet: None,
|
|
},
|
|
iface_ingress_tx,
|
|
iface_ingress_tx_avail,
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Device for VirtualDevice {
|
|
type RxToken<'a> = VirtualRxToken;
|
|
type TxToken<'a> = VirtualTxToken<'a>;
|
|
|
|
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
|
let buffer = if let Some(buf) = self.cached_packet.take() {
|
|
buf
|
|
} else {
|
|
let Ok(buf) = self.in_buf.try_recv() else {
|
|
self.in_buf_avail.store(false, Ordering::Release);
|
|
return None;
|
|
};
|
|
buf
|
|
};
|
|
|
|
let Ok(permit) = self.out_buf.try_reserve() else {
|
|
self.cached_packet = Some(buffer);
|
|
self.in_buf_avail.store(false, Ordering::Release);
|
|
return None;
|
|
};
|
|
|
|
Some((Self::RxToken { buffer }, Self::TxToken { permit }))
|
|
}
|
|
|
|
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
|
|
match self.out_buf.try_reserve() {
|
|
Ok(permit) => Some(Self::TxToken { permit }),
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
|
|
fn capabilities(&self) -> DeviceCapabilities {
|
|
let mut capabilities = DeviceCapabilities::default();
|
|
capabilities.medium = Medium::Ip;
|
|
capabilities.max_transmission_unit = self.mtu;
|
|
capabilities
|
|
}
|
|
}
|
|
|
|
pub(super) struct VirtualRxToken {
|
|
buffer: Vec<u8>,
|
|
}
|
|
|
|
impl RxToken for VirtualRxToken {
|
|
fn consume<R, F>(self, f: F) -> R
|
|
where
|
|
F: FnOnce(&[u8]) -> R,
|
|
{
|
|
f(&self.buffer[..])
|
|
}
|
|
}
|
|
|
|
pub(super) struct VirtualTxToken<'a> {
|
|
permit: Permit<'a, Vec<u8>>,
|
|
}
|
|
|
|
impl<'a> TxToken for VirtualTxToken<'a> {
|
|
fn consume<R, F>(self, len: usize, f: F) -> R
|
|
where
|
|
F: FnOnce(&mut [u8]) -> R,
|
|
{
|
|
let mut buffer = vec![0u8; len];
|
|
let result = f(&mut buffer);
|
|
self.permit.send(buffer);
|
|
result
|
|
}
|
|
}
|