use crate::tuntapinterfacedesc::TunTapInterfaceDesc; use smoltcp::{ phy::{self, Device, DeviceCapabilities, Medium}, time::Instant, }; use std::{ cell::RefCell, io, os::unix::io::{AsRawFd, RawFd}, rc::Rc, vec::Vec, }; /// A virtual TUN (IP) or TAP (Ethernet) interface. #[derive(Debug)] pub struct TunTapInterface { lower: Rc>, mtu: usize, medium: Medium, } impl AsRawFd for TunTapInterface { fn as_raw_fd(&self) -> RawFd { self.lower.borrow().as_raw_fd() } } impl TunTapInterface { /// Attaches to a TUN/TAP interface called `name`, or creates it if it does not exist. /// /// If `name` is a persistent interface configured with UID of the current user, /// no special privileges are needed. Otherwise, this requires superuser privileges /// or a corresponding capability set on the executable. pub fn new(name: &str, medium: Medium) -> io::Result { let lower = TunTapInterfaceDesc::new(name, medium)?; let mtu = lower.interface_mtu()?; Ok(TunTapInterface { lower: Rc::new(RefCell::new(lower)), mtu, medium, }) } /// Attaches to a TUN/TAP interface specified by file descriptor `fd`. /// /// On platforms like Android, a file descriptor to a tun interface is exposed. /// On these platforms, a TunTapInterface cannot be instantiated with a name. pub fn from_fd(fd: RawFd, medium: Medium, mtu: usize) -> io::Result { let lower = TunTapInterfaceDesc::from_fd(fd, mtu)?; Ok(TunTapInterface { lower: Rc::new(RefCell::new(lower)), mtu, medium, }) } } impl Device for TunTapInterface { type RxToken<'a> = RxToken; type TxToken<'a> = TxToken; fn capabilities(&self) -> DeviceCapabilities { let mut v = DeviceCapabilities::default(); v.max_transmission_unit = self.mtu; v.medium = self.medium; v } fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { let mut lower = self.lower.borrow_mut(); let mut buffer = vec![0; self.mtu]; match lower.recv(&mut buffer[..]) { Ok(size) => { buffer.resize(size, 0); let rx = RxToken { buffer }; let tx = TxToken { lower: self.lower.clone(), }; Some((rx, tx)) } Err(err) if err.kind() == io::ErrorKind::WouldBlock => None, Err(err) => panic!("{}", err), } } fn transmit(&mut self, _timestamp: Instant) -> Option> { Some(TxToken { lower: self.lower.clone(), }) } } #[doc(hidden)] pub struct RxToken { buffer: Vec, } impl phy::RxToken for RxToken { fn consume(mut self, f: F) -> R where F: FnOnce(&mut [u8]) -> R, { f(&mut self.buffer[..]) } } #[doc(hidden)] pub struct TxToken { lower: Rc>, } impl phy::TxToken for TxToken { fn consume(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R, { let mut lower = self.lower.borrow_mut(); let mut buffer = vec![0; len]; let result = f(&mut buffer); match lower.send(&buffer[..]) { Ok(_) => {} Err(err) if err.kind() == io::ErrorKind::WouldBlock => { log::error!("phy: tx failed due to WouldBlock") } Err(err) => panic!("{}", err), } result } }