From b49ba69d09576a4dd34fbc703a938acd50cb6e7a Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 16 Jun 2021 09:43:03 +0100 Subject: [PATCH] Add support for lirc programs Signed-off-by: Sean Young --- aya/src/bpf.rs | 6 +- aya/src/obj/mod.rs | 5 +- aya/src/programs/lirc_mode2.rs | 101 +++++++++++++++++++++++++++++++++ aya/src/programs/mod.rs | 12 +++- 4 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 aya/src/programs/lirc_mode2.rs diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 8e9137ad..33640239 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -19,8 +19,9 @@ use crate::{ Object, ParseError, ProgramKind, }, programs::{ - CgroupSkb, CgroupSkbAttachType, KProbe, ProbeKind, Program, ProgramData, ProgramError, - SchedClassifier, SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp, + CgroupSkb, CgroupSkbAttachType, KProbe, LircMode2, ProbeKind, Program, ProgramData, + ProgramError, SchedClassifier, SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, + UProbe, Xdp, }, sys::bpf_map_update_elem_ptr, util::{possible_cpus, POSSIBLE_CPUS}, @@ -195,6 +196,7 @@ impl Bpf { data, expected_attach_type: Some(CgroupSkbAttachType::Egress), }), + ProgramKind::LircMode2 => Program::LircMode2(LircMode2 { data }), }; (name, program) diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs index 72441019..44e53f4b 100644 --- a/aya/src/obj/mod.rs +++ b/aya/src/obj/mod.rs @@ -80,6 +80,7 @@ pub enum ProgramKind { SchedClassifier, CgroupSkbIngress, CgroupSkbEgress, + LircMode2, } impl FromStr for ProgramKind { @@ -102,6 +103,7 @@ impl FromStr for ProgramKind { "classifier" => SchedClassifier, "cgroup_skb/ingress" => CgroupSkbIngress, "cgroup_skb/egress" => CgroupSkbEgress, + "lirc_mode2" => LircMode2, _ => { return Err(ParseError::InvalidProgramKind { kind: kind.to_string(), @@ -302,7 +304,8 @@ impl Object { | &[ty @ "classifier", name] | &[ty @ "cgroup_skb/ingress", name] | &[ty @ "cgroup_skb/egress", name] - | &[ty @ "cgroup/skb", name] => { + | &[ty @ "cgroup/skb", name] + | &[ty @ "lirc_mode2", name] => { self.programs .insert(name.to_string(), self.parse_program(§ion, ty, name)?); if !section.relocations.is_empty() { diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs new file mode 100644 index 00000000..76700b97 --- /dev/null +++ b/aya/src/programs/lirc_mode2.rs @@ -0,0 +1,101 @@ +use std::os::unix::prelude::{AsRawFd, RawFd}; + +use crate::{ + generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2}, + programs::{load_program, Link, LinkRef, ProgramData, ProgramError}, + sys::{bpf_prog_attach, bpf_prog_detach}, +}; + +use libc::{close, dup}; + +/// A program used to decode IR into key events for a lirc device. +/// +/// [`LircMode2`] programs can be used to inspect infrared pulses, spaces, +/// and timeouts received by a lirc IR receiver. +/// +/// [lirc]: https://www.kernel.org/doc/html/latest/userspace-api/media/rc/lirc-dev.html +/// +/// # Examples +/// +/// ```no_run +/// use std::fs::File; +/// use std::convert::TryInto; +/// use aya::programs::LircMode2; +/// +/// let file = File::open("/dev/lirc0").unwrap(); +/// let mut bpf = Bpf::load_file("imon_rsc.o").unwrap(); +/// let decoder: &mut LircMode2 = bpf.program_mut("imon_rsc").unwrap().try_into().unwrap(); +/// decoder.load().unwrap(); +/// decoder.attach(file).unwrap(); +/// # Ok::<(), Error>(()) +/// ``` +#[derive(Debug)] +#[doc(alias = "BPF_PROG_TYPE_LIRC_MODE2")] +pub struct LircMode2 { + pub(crate) data: ProgramData, +} + +impl LircMode2 { + /// Loads the program inside the kernel. + /// + /// See also [`Program::load`](crate::programs::Program::load). + pub fn load(&mut self) -> Result<(), ProgramError> { + load_program(BPF_PROG_TYPE_LIRC_MODE2, &mut self.data) + } + + /// Returns the name of the program. + pub fn name(&self) -> String { + self.data.name.to_string() + } + + /// Attaches the program to the given lirc device. + pub fn attach(&mut self, lircdev: T) -> Result { + let prog_fd = self.data.fd_or_err()?; + let lircdev_fd = lircdev.as_raw_fd(); + + bpf_prog_attach(prog_fd, lircdev_fd, BPF_LIRC_MODE2).map_err(|(_, io_error)| { + ProgramError::SyscallError { + call: "bpf_prog_attach".to_owned(), + io_error, + } + })?; + + Ok(self.data.link(LircLink::new(prog_fd, lircdev_fd))) + } +} + +#[derive(Debug)] +struct LircLink { + prog_fd: Option, + target_fd: Option, +} + +impl LircLink { + pub(crate) fn new(prog_fd: RawFd, target_fd: RawFd) -> LircLink { + LircLink { + prog_fd: Some(prog_fd), + target_fd: Some(unsafe { dup(target_fd) }), + } + } +} + +impl Link for LircLink { + fn detach(&mut self) -> Result<(), ProgramError> { + if let Some(prog_fd) = self.prog_fd.take() { + let target_fd = self.target_fd.take().unwrap(); + let _ = bpf_prog_detach(prog_fd, target_fd, BPF_LIRC_MODE2); + unsafe { close(target_fd) }; + Ok(()) + } else { + Err(ProgramError::AlreadyDetached) + } + } +} + +impl Drop for LircLink { + fn drop(&mut self) { + if let Some(target_fd) = self.target_fd.take() { + unsafe { close(target_fd) }; + } + } +} diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 805f4a49..88552af9 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -38,6 +38,7 @@ //! [`maps`]: crate::maps mod cgroup_skb; mod kprobe; +mod lirc_mode2; mod perf_attach; mod probe; mod sk_msg; @@ -55,6 +56,7 @@ use thiserror::Error; pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType}; pub use kprobe::{KProbe, KProbeError}; +pub use lirc_mode2::LircMode2; use perf_attach::*; pub use probe::ProbeKind; pub use sk_msg::SkMsg; @@ -170,6 +172,7 @@ pub enum Program { SockOps(SockOps), SchedClassifier(SchedClassifier), CgroupSkb(CgroupSkb), + LircMode2(LircMode2), } impl Program { @@ -201,6 +204,7 @@ impl Program { Program::SockOps(_) => BPF_PROG_TYPE_SOCK_OPS, Program::SchedClassifier(_) => BPF_PROG_TYPE_SCHED_CLS, Program::CgroupSkb(_) => BPF_PROG_TYPE_CGROUP_SKB, + Program::LircMode2(_) => BPF_PROG_TYPE_LIRC_MODE2, } } @@ -221,6 +225,7 @@ impl Program { Program::SockOps(p) => &p.data, Program::SchedClassifier(p) => &p.data, Program::CgroupSkb(p) => &p.data, + Program::LircMode2(p) => &p.data, } } @@ -236,6 +241,7 @@ impl Program { Program::SockOps(p) => &mut p.data, Program::SchedClassifier(p) => &mut p.data, Program::CgroupSkb(p) => &mut p.data, + Program::LircMode2(p) => &mut p.data, } } } @@ -482,7 +488,8 @@ impl_program_fd!( SkMsg, SkSkb, SchedClassifier, - CgroupSkb + CgroupSkb, + LircMode2 ); macro_rules! impl_try_from_program { @@ -523,5 +530,6 @@ impl_try_from_program!( SkSkb, SockOps, SchedClassifier, - CgroupSkb + CgroupSkb, + LircMode2 );