Skip to content

Commit

Permalink
Report if the kernel doesn't support bpf ir decoders
Browse files Browse the repository at this point in the history
Signed-off-by: Sean Young <[email protected]>
  • Loading branch information
seanyoung committed May 11, 2024
1 parent 063d8a5 commit 91b4c2f
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 11 deletions.
1 change: 0 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Necessary:
Nice to have:
- ir encode/send needs to read xml file
- cir decode irp should read IrpProtocols.xml
- access to io_error in aya
- cir transmit rawir -S sony15:12 -r 2 ??
- pcmak leading gap not decoded
- encoding toggle_bit_mask not used when popcount > 1
Expand Down
57 changes: 53 additions & 4 deletions src/bin/commands/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,22 @@ pub fn config(config: &crate::Config) {
};

if !lirc.can_receive_raw() {
eprintln!(
"error: {}: not a raw receiver, irp not supported",
rcdev.name
);
eprintln!("error: {}: not a raw receiver, irp not supported", lircdev);
std::process::exit(1);
}

match lirc.query_bpf() {
Ok(Some(_)) => (),
Ok(None) => {
eprintln!("error: {}: no kernel BPF support, rebuild kernel with CONFIG_BPF_LIRC_MODE2", lircdev);
std::process::exit(1);
}
Err(e) => {
eprintln!("error: {}: {e}", lircdev);
std::process::exit(1);
}
}

lirc
} else {
eprintln!("error: {}: no lirc device, irp not supported", rcdev.name);
Expand Down Expand Up @@ -475,6 +484,26 @@ fn load_keymap(
}
};

if !chdev.can_receive_raw() {
eprintln!("error: {}: not a raw receiver, irp not supported", chdev);
std::process::exit(1);
}

match chdev.query_bpf() {
Ok(Some(_)) => (),
Ok(None) => {
eprintln!(
"error: {}: no kernel BPF support, rebuild kernel with CONFIG_BPF_LIRC_MODE2",
chdev
);
std::process::exit(1);
}
Err(e) => {
eprintln!("error: {}: {e}", chdev);
std::process::exit(1);
}
}

if let Err(e) = chdev.attach_bpf(&bpf) {
eprintln!("error: {}: attach bpf: {e}", keymap_filename.display());
std::process::exit(1);
Expand Down Expand Up @@ -546,6 +575,26 @@ fn load_lircd(
}
};

if !chdev.can_receive_raw() {
eprintln!("error: {}: not a raw receiver, irp not supported", chdev);
std::process::exit(1);
}

match chdev.query_bpf() {
Ok(Some(_)) => (),
Ok(None) => {
eprintln!(
"error: {}: no kernel BPF support, rebuild kernel with CONFIG_BPF_LIRC_MODE2",
chdev
);
std::process::exit(1);
}
Err(e) => {
eprintln!("error: {}: {e}", chdev);
std::process::exit(1);
}
}

if let Err(e) = chdev.attach_bpf(&bpf) {
eprintln!("error: {}: attach bpf: {e}", keymap_filename.display());
std::process::exit(1);
Expand Down
5 changes: 4 additions & 1 deletion src/bin/commands/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,12 @@ fn print_rc_dev(list: &[rcdev::Rcdev], config: &crate::List) {

if lircdev.can_receive_raw() {
match lircdev.query_bpf() {
Ok(links) => {
Ok(Some(links)) => {
println!("\tBPF protocols\t\t: {}", links.iter().join(" "));
}
Ok(None) => {
println!("\tBPF protocols\t\t: No kernel support")
}
Err(err) => {
println!("\tBPF protocols\t\t: {err}")
}
Expand Down
45 changes: 40 additions & 5 deletions src/lirc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,17 @@ impl Lirc {
}
}

/// query bpf programs
pub fn query_bpf(&self) -> Result<Vec<String>, ProgramError> {
let links = LircMode2::query(self.as_fd())?;
/// Query bpf programs attached to lirc dev. Returns Ok(None) if there is no support
/// for bpf programs with the current kernel.
pub fn query_bpf(&self) -> Result<Option<Vec<String>>, ProgramError> {
let res = LircMode2::query(self.as_fd());

if res.as_ref().is_err_and(is_syscall_unsupported) {
return Ok(None);
}

let links = res?;

let mut res = Vec::new();

for link in links {
Expand All @@ -517,15 +525,23 @@ impl Lirc {
}
}

Ok(res)
Ok(Some(res))
}

/// Remove all attached bpf programs
pub fn clear_bpf(&self) -> Result<(), ProgramError> {
let links = LircMode2::query(self.as_fd())?;
let res = LircMode2::query(self.as_fd());

if res.as_ref().is_err_and(is_syscall_unsupported) {
return Ok(());
}

let links = res?;

for link in links {
link.detach()?;
}

Ok(())
}
}
Expand All @@ -547,3 +563,22 @@ impl fmt::Display for Lirc {
write!(f, "{}", self.path.display())
}
}

/// If LircMode2::query() fails, is this due to the syscall not being supported,
/// or another reason (e.g. permission denied)
fn is_syscall_unsupported(error: &ProgramError) -> bool {
if let ProgramError::SyscallError(syscall_error) = &error {
// No support for the syscall
if syscall_error.call == "bpf_prog_query"
// kernel not built with CONFIG_BPF_LIRC_MODE2
&& syscall_error.io_error.kind() == ErrorKind::InvalidInput
// kernel not built with CONFIG_BPF_SYSCALL
|| syscall_error.io_error.kind() == ErrorKind::Unsupported
{
return true;
}
}

// another reason (permission denied, not sure what else could go wrong)
false
}

0 comments on commit 91b4c2f

Please sign in to comment.