use core::mem;
#[cfg(feature = "std")]
use std::os::unix::io::{RawFd, AsRawFd};
use libc;
use super::{ifreq, linux, now, Errno, FdResult, LibcResult, IoLenResult};
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::linux::IfIndex;
#[cfg(target_os = "linux")]
pub(crate) use super::linux::NetdeviceMtu;
}
use tap_traits::{IfIndex, NetdeviceMtu};
#[derive(Debug)]
pub struct RawSocketDesc {
lower: libc::c_int,
ifreq: ifreq
}
#[derive(Debug)]
pub struct RawSocket<C> {
inner: RawSocketDesc,
buffer: Partial<C>,
last_err: Option<Errno>,
capabilities: Capabilities,
}
enum Received {
NoData,
Ok,
Err(crate::layer::Error),
}
#[cfg(feature = "std")]
impl AsRawFd for RawSocketDesc {
fn as_raw_fd(&self) -> RawFd {
self.lower
}
}
#[cfg(feature = "std")]
impl<C> AsRawFd for RawSocket<C> {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}
impl RawSocketDesc {
pub fn new(name: &str) -> Result<RawSocketDesc, Errno> {
let lower = unsafe {
libc::socket(
libc::AF_PACKET,
libc::SOCK_RAW | libc::SOCK_NONBLOCK,
linux::ETH_P_ALL.to_be() as i32)
};
FdResult(lower).errno()?;
Ok(RawSocketDesc {
lower,
ifreq: ifreq::new(name),
})
}
pub fn interface_mtu(&mut self) -> Result<usize, Errno> {
self.ifreq.get_mtu(self.lower)
.map(|mtu| mtu as usize)
}
pub fn bind_interface(&mut self) -> Result<(), Errno> {
let sockaddr = libc::sockaddr_ll {
sll_family: libc::AF_PACKET as u16,
sll_protocol: linux::ETH_P_ALL.to_be() as u16,
sll_ifindex: self.ifreq.get_if_index(self.lower)?,
sll_hatype: 1,
sll_pkttype: 0,
sll_halen: 6,
sll_addr: [0; 8],
};
let res = unsafe {
libc::bind(
self.lower,
&sockaddr as *const libc::sockaddr_ll as *const libc::sockaddr,
mem::size_of::<libc::sockaddr_ll>() as u32)
};
FdResult(res).errno()
}
pub fn recv(&mut self, buffer: &mut [u8]) -> Result<usize, Errno> {
let len = unsafe {
libc::recv(
self.lower,
buffer.as_mut_ptr() as *mut libc::c_void,
buffer.len(),
0)
};
IoLenResult(len).errno()?;
Ok(len as usize)
}
pub fn send(&mut self, buffer: &[u8]) -> Result<usize, Errno> {
let len = unsafe {
libc::send(
self.lower,
buffer.as_ptr() as *const libc::c_void,
buffer.len(),
0)
};
IoLenResult(len).errno()?;
Ok(len as usize)
}
}
impl<C: PayloadMut> RawSocket<C> {
pub fn new(name: &str, buffer: C) -> Result<Self, Errno> {
let mut inner = RawSocketDesc::new(name)?;
inner.bind_interface()?;
Self::with_descriptor(inner, buffer)
}
pub fn with_descriptor(
inner: RawSocketDesc,
buffer: C,
) -> Result<Self, Errno> {
Ok(RawSocket {
inner,
buffer: Partial::new(buffer),
last_err: None,
capabilities: Capabilities::no_support(),
})
}
pub fn capabilities(&self) -> Capabilities {
self.capabilities
}
pub fn capabilities_mut(&mut self) -> &mut Capabilities {
&mut self.capabilities
}
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 = crate::layer::Error::Illegal;
self.last_err = Some(err);
as_nic
}
fn current_info(&self) -> PacketInfo {
PacketInfo {
timestamp: now().unwrap(),
capabilities: self.capabilities,
}
}
}
impl Drop for RawSocketDesc {
fn drop(&mut self) {
unsafe { libc::close(self.lower); }
}
}
impl<C: PayloadMut> Device for RawSocket<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)
}
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)
}
}