use std::os::fd::{AsFd, AsRawFd as _, RawFd};
use crate::{
generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2},
programs::{
load_program, query, CgroupAttachMode, Link, ProgramData, ProgramError, ProgramFd,
ProgramInfo,
},
sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, ProgQueryTarget},
};
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_LIRC_MODE2")]
pub struct LircMode2 {
pub(crate) data: ProgramData<LircLink>,
}
impl LircMode2 {
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_LIRC_MODE2, &mut self.data)
}
pub fn attach<T: AsFd>(&mut self, lircdev: T) -> Result<LircLinkId, ProgramError> {
let prog_fd = self.fd()?;
let prog_fd = prog_fd.try_clone()?;
let lircdev_fd = lircdev.as_fd().try_clone_to_owned()?;
let lircdev_fd = crate::MockableFd::from_fd(lircdev_fd);
bpf_prog_attach(
prog_fd.as_fd(),
lircdev_fd.as_fd(),
BPF_LIRC_MODE2,
CgroupAttachMode::Single.into(),
)?;
self.data.links.insert(LircLink::new(prog_fd, lircdev_fd))
}
pub fn detach(&mut self, link_id: LircLinkId) -> Result<(), ProgramError> {
self.data.links.remove(link_id)
}
pub fn take_link(&mut self, link_id: LircLinkId) -> Result<LircLink, ProgramError> {
self.data.take_link(link_id)
}
pub fn query<T: AsFd>(target_fd: T) -> Result<Vec<LircLink>, ProgramError> {
let target_fd = target_fd.as_fd();
let (_, prog_ids) = query(ProgQueryTarget::Fd(target_fd), BPF_LIRC_MODE2, 0, &mut None)?;
prog_ids
.into_iter()
.map(|prog_id| {
let prog_fd = bpf_prog_get_fd_by_id(prog_id)?;
let target_fd = target_fd.try_clone_to_owned()?;
let target_fd = crate::MockableFd::from_fd(target_fd);
let prog_fd = ProgramFd(prog_fd);
Ok(LircLink::new(prog_fd, target_fd))
})
.collect()
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct LircLinkId(RawFd, RawFd);
#[derive(Debug)]
pub struct LircLink {
prog_fd: ProgramFd,
target_fd: crate::MockableFd,
}
impl LircLink {
pub(crate) fn new(prog_fd: ProgramFd, target_fd: crate::MockableFd) -> Self {
Self { prog_fd, target_fd }
}
pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
let Self {
prog_fd,
target_fd: _,
} = self;
ProgramInfo::new_from_fd(prog_fd.as_fd())
}
}
impl Link for LircLink {
type Id = LircLinkId;
fn id(&self) -> Self::Id {
LircLinkId(self.prog_fd.as_fd().as_raw_fd(), self.target_fd.as_raw_fd())
}
fn detach(self) -> Result<(), ProgramError> {
bpf_prog_detach(self.prog_fd.as_fd(), self.target_fd.as_fd(), BPF_LIRC_MODE2)
.map_err(Into::into)
}
}