summaryrefslogtreecommitdiff
path: root/src/phy/tuntap_interface.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/phy/tuntap_interface.rs')
-rw-r--r--src/phy/tuntap_interface.rs126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/phy/tuntap_interface.rs b/src/phy/tuntap_interface.rs
new file mode 100644
index 0000000..32a28db
--- /dev/null
+++ b/src/phy/tuntap_interface.rs
@@ -0,0 +1,126 @@
+use std::cell::RefCell;
+use std::io;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::rc::Rc;
+use std::vec::Vec;
+
+use crate::phy::{self, sys, Device, DeviceCapabilities, Medium};
+use crate::time::Instant;
+
+/// A virtual TUN (IP) or TAP (Ethernet) interface.
+#[derive(Debug)]
+pub struct TunTapInterface {
+ lower: Rc<RefCell<sys::TunTapInterfaceDesc>>,
+ 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<TunTapInterface> {
+ let lower = sys::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<TunTapInterface> {
+ let lower = sys::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 {
+ DeviceCapabilities {
+ max_transmission_unit: self.mtu,
+ medium: self.medium,
+ ..DeviceCapabilities::default()
+ }
+ }
+
+ 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<Self::TxToken<'_>> {
+ Some(TxToken {
+ lower: self.lower.clone(),
+ })
+ }
+}
+
+#[doc(hidden)]
+pub struct RxToken {
+ buffer: Vec<u8>,
+}
+
+impl phy::RxToken for RxToken {
+ fn consume<R, F>(mut self, f: F) -> R
+ where
+ F: FnOnce(&mut [u8]) -> R,
+ {
+ f(&mut self.buffer[..])
+ }
+}
+
+#[doc(hidden)]
+pub struct TxToken {
+ lower: Rc<RefCell<sys::TunTapInterfaceDesc>>,
+}
+
+impl phy::TxToken for TxToken {
+ fn consume<R, F>(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 => {
+ net_debug!("phy: tx failed due to WouldBlock")
+ }
+ Err(err) => panic!("{}", err),
+ }
+ result
+ }
+}