use neli::{
consts::{
nl::{NlmF, NlmFFlags, NlType},
rtnl::{Arphrd, RtAddrFamily, Rtm},
socket::NlFamily,
},
err::NlError,
nl::{Nlmsghdr, NlPayload},
rtnl::Ifinfomsg,
ToBytes,
types::RtBuffer,
socket::NlSocketHandle,
};
use nix::{self, unistd, net::if_::if_nametoindex};
use std::{
os::raw::{c_int, c_uint},
fmt::Debug,
};
type NlResult<T> = Result<T, NlError>;
pub struct CanInterface {
if_index: c_uint,
}
impl CanInterface {
pub fn open(ifname: &str) -> Result<Self, nix::Error> {
let if_index = if_nametoindex(ifname)?;
Ok(Self::open_iface(if_index))
}
pub fn open_iface(if_index: u32) -> Self {
Self { if_index: if_index as c_uint }
}
fn send_info_msg(info: Ifinfomsg) -> NlResult<()> {
let mut nl = Self::open_route_socket()?;
let hdr = Nlmsghdr::new(
None,
Rtm::Newlink,
NlmFFlags::new(&[NlmF::Request, NlmF::Ack]),
None,
None,
NlPayload::Payload(info),
);
Self::send_and_read_ack(&mut nl, hdr)
}
fn send_and_read_ack<T, P>(sock: &mut NlSocketHandle, msg: Nlmsghdr<T, P>) -> NlResult<()>
where
T: NlType + Debug,
P: ToBytes + Debug,
{
sock.send(msg)?;
Ok(())
}
fn open_route_socket() -> NlResult<NlSocketHandle> {
let pid = unistd::getpid().as_raw() as u32;
let sock = NlSocketHandle::connect(NlFamily::Route, Some(pid), &[])?;
Ok(sock)
}
pub fn bring_down(&self) -> NlResult<()> {
let info = Ifinfomsg::down(
RtAddrFamily::Unspecified,
Arphrd::Netrom,
self.if_index as c_int,
RtBuffer::new()
);
Self::send_info_msg(info)
}
pub fn bring_up(&self) -> NlResult<()> {
let info = Ifinfomsg::up(
RtAddrFamily::Unspecified,
Arphrd::Netrom,
self.if_index as c_int,
RtBuffer::new()
);
Self::send_info_msg(info)
}
}