kratanet/
chandev.rs

1// Referenced https://github.com/vi/wgslirpy/blob/master/crates/libwgslirpy/src/channelized_smoltcp_device.rs
2use bytes::BytesMut;
3use log::{debug, warn};
4use smoltcp::phy::{Checksum, Device, Medium};
5use tokio::sync::mpsc::Sender;
6
7const TEAR_OFF_BUFFER_SIZE: usize = 65536;
8
9pub struct ChannelDevice {
10    pub mtu: usize,
11    pub medium: Medium,
12    pub tx: Sender<BytesMut>,
13    pub rx: Option<BytesMut>,
14    tear_off_buffer: BytesMut,
15}
16
17impl ChannelDevice {
18    pub fn new(mtu: usize, medium: Medium, tx: Sender<BytesMut>) -> Self {
19        Self {
20            mtu,
21            medium,
22            tx,
23            rx: None,
24            tear_off_buffer: BytesMut::with_capacity(TEAR_OFF_BUFFER_SIZE),
25        }
26    }
27}
28
29pub struct RxToken(pub BytesMut);
30
31impl Device for ChannelDevice {
32    type RxToken<'a> = RxToken where Self: 'a;
33    type TxToken<'a> = &'a mut ChannelDevice where Self: 'a;
34
35    fn receive(
36        &mut self,
37        _timestamp: smoltcp::time::Instant,
38    ) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
39        self.rx.take().map(|x| (RxToken(x), self))
40    }
41
42    fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
43        if self.tx.capacity() == 0 {
44            debug!("ran out of transmission capacity");
45            return None;
46        }
47        Some(self)
48    }
49
50    fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
51        let mut capabilities = smoltcp::phy::DeviceCapabilities::default();
52        capabilities.medium = self.medium;
53        capabilities.max_transmission_unit = self.mtu;
54        capabilities.checksum = smoltcp::phy::ChecksumCapabilities::ignored();
55        capabilities.checksum.tcp = Checksum::Tx;
56        capabilities.checksum.ipv4 = Checksum::Tx;
57        capabilities.checksum.icmpv4 = Checksum::Tx;
58        capabilities.checksum.icmpv6 = Checksum::Tx;
59        capabilities
60    }
61}
62
63impl smoltcp::phy::RxToken for RxToken {
64    fn consume<R, F>(mut self, f: F) -> R
65    where
66        F: FnOnce(&mut [u8]) -> R,
67    {
68        f(&mut self.0[..])
69    }
70}
71
72impl<'a> smoltcp::phy::TxToken for &'a mut ChannelDevice {
73    fn consume<R, F>(self, len: usize, f: F) -> R
74    where
75        F: FnOnce(&mut [u8]) -> R,
76    {
77        self.tear_off_buffer.resize(len, 0);
78        let result = f(&mut self.tear_off_buffer[..]);
79        let chunk = self.tear_off_buffer.split();
80        if let Err(error) = self.tx.try_send(chunk) {
81            warn!("failed to transmit packet: {}", error);
82        }
83
84        if self.tear_off_buffer.capacity() < self.mtu {
85            self.tear_off_buffer = BytesMut::with_capacity(TEAR_OFF_BUFFER_SIZE);
86        }
87        result
88    }
89}