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, in_buf: UnboundedReceiver>, out_buf: Sender, mtu: usize, cached_packet: Option>, } impl VirtualDevice { pub(super) fn new( iface_egress_tx: Sender, mtu: usize, ) -> (Self, UnboundedSender>, Arc) { 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> { 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, } impl RxToken for VirtualRxToken { fn consume(self, f: F) -> R where F: FnOnce(&[u8]) -> R, { f(&self.buffer[..]) } } pub(super) struct VirtualTxToken<'a> { permit: Permit<'a, Vec>, } impl<'a> TxToken for VirtualTxToken<'a> { fn consume(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 } }