use std::io;
use std::os::unix::io::{AsRawFd, RawFd};
use libc;
use super::{ifreq, ifreq_for};
#[cfg(target_os = "macos")]
const BIOCSETIF: libc::c_ulong = 0x8020426c;
#[cfg(target_os = "macos")]
const BIOCGBLEN: libc::c_ulong = 0x40044266;
#[cfg(target_os = "macos")]
const BIOCIMMEDIATE: libc::c_ulong = 0x80044270;
#[cfg(target_os = "macos")]
const BPF_HDRLEN: usize = 18;
macro_rules! try_ioctl {
($fd:expr,$cmd:expr,$req:expr) => {
unsafe {
if libc::ioctl($fd, $cmd, $req) == -1 {
return Err(io::Error::last_os_error());
}
}
};
}
#[derive(Debug)]
pub struct BpfDevice {
fd: libc::c_int,
ifreq: ifreq,
}
impl AsRawFd for BpfDevice {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
fn open_device() -> io::Result<libc::c_int> {
unsafe {
for i in 0..256 {
let dev = format!("/dev/bpf{}", i).as_ptr() as *const libc::c_char;
match libc::open(dev, libc::O_RDWR) {
-1 => continue,
fd => return Ok(fd),
};
}
}
Err(io::Error::last_os_error())
}
impl BpfDevice {
pub fn new(name: &str) -> io::Result<BpfDevice> {
Ok(BpfDevice {
fd: open_device()?,
ifreq: ifreq_for(name),
})
}
pub fn bind_interface(&mut self) -> io::Result<()> {
try_ioctl!(self.fd, BIOCSETIF, &mut self.ifreq);
Ok(())
}
pub fn interface_mtu(&mut self) -> io::Result<usize> {
let mut bufsize: libc::c_int = 1;
try_ioctl!(self.fd, BIOCIMMEDIATE, &mut bufsize as *mut libc::c_int);
try_ioctl!(self.fd, BIOCGBLEN, &mut bufsize as *mut libc::c_int);
Ok(bufsize as usize)
}
pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
unsafe {
let len = libc::read(
self.fd,
buffer.as_mut_ptr() as *mut libc::c_void,
buffer.len(),
);
if len == -1 || len < BPF_HDRLEN as isize {
return Err(io::Error::last_os_error());
}
let len = len as usize;
libc::memmove(
buffer.as_mut_ptr() as *mut libc::c_void,
&buffer[BPF_HDRLEN] as *const u8 as *const libc::c_void,
len - BPF_HDRLEN,
);
Ok(len)
}
}
pub fn send(&mut self, buffer: &[u8]) -> io::Result<usize> {
unsafe {
let len = libc::write(
self.fd,
buffer.as_ptr() as *const libc::c_void,
buffer.len(),
);
if len == -1 {
Err(io::Error::last_os_error()).unwrap()
}
Ok(len as usize)
}
}
}
impl Drop for BpfDevice {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}