#[cfg(feature = "std")]
use std::os::unix::io::{RawFd, AsRawFd};
use libc;
use super::{now, Errno, FdResult, IoLenResult, LibcResult, ifreq};
use crate::nic::{self, Capabilities, Device, Packet, Personality};
use crate::nic::common::{EnqueueFlag, PacketInfo};
use crate::managed::Partial;
use crate::wire::PayloadMut;
mod tap_traits {
#[cfg(target_os = "linux")]
pub(crate) use super::super::linux::TunSetIf;
#[cfg(target_os = "linux")]
pub(crate) use super::super::linux::NetdeviceMtu;
}
use tap_traits::{NetdeviceMtu, TunSetIf};
#[derive(Debug)]
pub struct TapInterfaceDesc {
lower: libc::c_int,
ifreq: ifreq
}
#[derive(Debug)]
pub struct TapInterface<C> {
inner: TapInterfaceDesc,
buffer: Partial<C>,
last_err: Option<Errno>,
}
enum Received {
NoData,
Ok,
Err(crate::layer::Error),
}
#[cfg(feature = "std")]
impl AsRawFd for TapInterfaceDesc {
fn as_raw_fd(&self) -> RawFd {
self.lower
}
}
#[cfg(feature = "std")]
impl<C> AsRawFd for TapInterface<C> {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}
static TAP_PATH: &'static [u8] = b"/dev/net/tun\0";
impl TapInterfaceDesc {
pub fn new(name: &str) -> Result<TapInterfaceDesc, Errno> {
let lower = unsafe {
libc::open(
TAP_PATH.as_ptr() as *const libc::c_char,
libc::O_RDWR | libc::O_NONBLOCK)
};
FdResult(lower).errno()?;
Ok(TapInterfaceDesc {
lower,
ifreq: ifreq::new(name),
})
}
pub fn attach_interface(&mut self) -> Result<(), Errno> {
self.ifreq.tun_set_tap(self.lower)
}
pub fn interface_mtu(&mut self) -> Result<usize, Errno> {
let lower = unsafe {
libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP)
};
FdResult(lower).errno()?;
let mtu = self.ifreq.get_mtu(self.lower)
.map(|mtu| mtu as usize);
unsafe { libc::close(lower); }
mtu
}
pub fn recv(&mut self, buffer: &mut [u8]) -> Result<usize, Errno> {
let len = unsafe {
libc::read(
self.lower,
buffer.as_mut_ptr() as *mut libc::c_void,
buffer.len())
};
IoLenResult(len).errno()?;
Ok(len as usize)
}
pub fn send(&mut self, buffer: &[u8]) -> Result<usize, Errno> {
let len = unsafe {
libc::write(
self.lower,
buffer.as_ptr() as *const libc::c_void,
buffer.len())
};
IoLenResult(len).errno()?;
Ok(len as usize)
}
}
impl<C: PayloadMut> TapInterface<C> {
pub fn new(name: &str, buffer: C) -> Result<Self, Errno> {
let inner = TapInterfaceDesc::new(name)?;
Self::with_descriptor(inner, buffer)
}
pub fn with_descriptor(
mut inner: TapInterfaceDesc,
buffer: C,
) -> Result<Self, Errno> {
inner.attach_interface()?;
Ok(TapInterface {
inner,
buffer: Partial::new(buffer),
last_err: None,
})
}
pub fn last_err(&mut self) -> Option<Errno> {
self.last_err.take()
}
fn recycle(&mut self) {
let length = self.buffer
.inner()
.payload()
.as_slice()
.len();
self.buffer.set_len_unchecked(length);
}
fn send(&mut self) -> nic::Result<()> {
let result = self.inner.send(self.buffer.payload_mut().as_mut_slice());
match result {
Ok(_) => Ok(()),
Err(err) => Err(self.store_err(err))
}
}
fn recv(&mut self) -> Received {
self.recycle();
let result = self.inner.recv(self.buffer.payload_mut().as_mut_slice());
match result {
Ok(len) => {
self.buffer.set_len_unchecked(len);
Received::Ok
},
Err(ref err) if err.0 == libc::EWOULDBLOCK => Received::NoData,
Err(err) => Received::Err(self.store_err(err)),
}
}
fn store_err(&mut self, err: Errno) -> crate::layer::Error {
let as_nic = io_error_to_layer(&err);
self.last_err = Some(err);
as_nic
}
fn current_info() -> PacketInfo {
PacketInfo {
timestamp: now().unwrap(),
capabilities: Capabilities::no_support(),
}
}
}
impl Drop for TapInterfaceDesc {
fn drop(&mut self) {
unsafe { libc::close(self.lower); }
}
}
impl<C: PayloadMut> Device for TapInterface<C> {
type Handle = EnqueueFlag;
type Payload = Partial<C>;
fn personality(&self) -> Personality {
Personality::baseline()
}
fn tx(&mut self, _: usize, mut sender: impl nic::Send<Self::Handle, Self::Payload>)
-> nic::Result<usize>
{
let mut handle = EnqueueFlag::set_true(Self::current_info());
self.recycle();
sender.send(Packet {
handle: &mut handle,
payload: &mut self.buffer,
});
if handle.was_sent() {
self.send()?;
Ok(1)
} else {
Ok(0)
}
}
fn rx(&mut self, _: usize, mut receptor: impl nic::Recv<Self::Handle, Self::Payload>)
-> nic::Result<usize>
{
match self.recv() {
Received::Ok => (),
Received::Err(err) => return Err(err),
Received::NoData => return Ok(0),
}
let mut handle = EnqueueFlag::set_true(Self::current_info());
receptor.receive(Packet {
handle: &mut handle,
payload: &mut self.buffer,
});
if handle.was_sent() {
self.send()?;
}
Ok(1)
}
}
fn io_error_to_layer(_: &Errno) -> crate::layer::Error {
crate::layer::Error::Illegal
}