smoltcp/phy/
tuntap_interface.rs

1use std::cell::RefCell;
2use std::io;
3use std::os::unix::io::{AsRawFd, RawFd};
4use std::rc::Rc;
5use std::vec::Vec;
6
7use crate::phy::{self, sys, Device, DeviceCapabilities, Medium};
8use crate::time::Instant;
9
10/// A virtual TUN (IP) or TAP (Ethernet) interface.
11#[derive(Debug)]
12pub struct TunTapInterface {
13    lower: Rc<RefCell<sys::TunTapInterfaceDesc>>,
14    mtu: usize,
15    medium: Medium,
16}
17
18impl AsRawFd for TunTapInterface {
19    fn as_raw_fd(&self) -> RawFd {
20        self.lower.borrow().as_raw_fd()
21    }
22}
23
24impl TunTapInterface {
25    /// Attaches to a TUN/TAP interface called `name`, or creates it if it does not exist.
26    ///
27    /// If `name` is a persistent interface configured with UID of the current user,
28    /// no special privileges are needed. Otherwise, this requires superuser privileges
29    /// or a corresponding capability set on the executable.
30    pub fn new(name: &str, medium: Medium) -> io::Result<TunTapInterface> {
31        let lower = sys::TunTapInterfaceDesc::new(name, medium)?;
32        let mtu = lower.interface_mtu()?;
33        Ok(TunTapInterface {
34            lower: Rc::new(RefCell::new(lower)),
35            mtu,
36            medium,
37        })
38    }
39
40    /// Attaches to a TUN/TAP interface specified by file descriptor `fd`.
41    ///
42    /// On platforms like Android, a file descriptor to a tun interface is exposed.
43    /// On these platforms, a TunTapInterface cannot be instantiated with a name.
44    pub fn from_fd(fd: RawFd, medium: Medium, mtu: usize) -> io::Result<TunTapInterface> {
45        let lower = sys::TunTapInterfaceDesc::from_fd(fd, mtu)?;
46        Ok(TunTapInterface {
47            lower: Rc::new(RefCell::new(lower)),
48            mtu,
49            medium,
50        })
51    }
52}
53
54impl Device for TunTapInterface {
55    type RxToken<'a> = RxToken;
56    type TxToken<'a> = TxToken;
57
58    fn capabilities(&self) -> DeviceCapabilities {
59        DeviceCapabilities {
60            max_transmission_unit: self.mtu,
61            medium: self.medium,
62            ..DeviceCapabilities::default()
63        }
64    }
65
66    fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
67        let mut lower = self.lower.borrow_mut();
68        let mut buffer = vec![0; self.mtu];
69        match lower.recv(&mut buffer[..]) {
70            Ok(size) => {
71                buffer.resize(size, 0);
72                let rx = RxToken { buffer };
73                let tx = TxToken {
74                    lower: self.lower.clone(),
75                };
76                Some((rx, tx))
77            }
78            Err(err) if err.kind() == io::ErrorKind::WouldBlock => None,
79            Err(err) => panic!("{}", err),
80        }
81    }
82
83    fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
84        Some(TxToken {
85            lower: self.lower.clone(),
86        })
87    }
88}
89
90#[doc(hidden)]
91pub struct RxToken {
92    buffer: Vec<u8>,
93}
94
95impl phy::RxToken for RxToken {
96    fn consume<R, F>(self, f: F) -> R
97    where
98        F: FnOnce(&[u8]) -> R,
99    {
100        f(&self.buffer[..])
101    }
102}
103
104#[doc(hidden)]
105pub struct TxToken {
106    lower: Rc<RefCell<sys::TunTapInterfaceDesc>>,
107}
108
109impl phy::TxToken for TxToken {
110    fn consume<R, F>(self, len: usize, f: F) -> R
111    where
112        F: FnOnce(&mut [u8]) -> R,
113    {
114        let mut lower = self.lower.borrow_mut();
115        let mut buffer = vec![0; len];
116        let result = f(&mut buffer);
117        match lower.send(&buffer[..]) {
118            Ok(_) => {}
119            Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
120                net_debug!("phy: tx failed due to WouldBlock")
121            }
122            Err(err) => panic!("{}", err),
123        }
124        result
125    }
126}