use errno::Errno;
use libc::{self, nlmsgerr};
use {CbResult, CbStatus, Msghdr};
pub const NOCB: Option<fn(&Msghdr) -> CbResult> = None;
fn noop(_nlh: &Msghdr) -> CbResult {
Ok(CbStatus::Ok)
}
fn error(nlh: &Msghdr) -> CbResult {
let err = nlh.payload::<nlmsgerr>()?;
match err.error {
e if e < 0 => crate::gen_errno!(-err.error),
e if e > 0 => crate::gen_errno!(err.error),
_ => Ok(CbStatus::Stop),
}
}
fn stop(_nlh: &Msghdr) -> CbResult {
Ok(CbStatus::Stop)
}
const DEFAULT_CB_ARRAY: [Option<fn(&Msghdr) -> CbResult>; libc::NLMSG_MIN_TYPE as usize] = [
None,
Some(noop), Some(error), Some(stop), Some(noop), None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
];
fn __run<'a, T, U>(
buf: &'a [u8],
seq: u32,
portid: u32,
mut cb_data: Option<T>,
cb_ctl_array: &mut [Option<U>],
) -> CbResult
where
T: FnMut(&'a Msghdr<'a>) -> CbResult,
U: FnMut(&'a Msghdr<'a>) -> CbResult,
{
let mut nlh = unsafe { &*(buf.as_ptr() as *const _ as *const Msghdr) };
let mut len = buf.len() as isize;
if !nlh.ok(len) {
return crate::gen_errno!(libc::EBADMSG);
}
loop {
nlh.portid_ok(portid)?;
nlh.seq_ok(seq)?;
if nlh.nlmsg_flags & libc::NLM_F_DUMP_INTR as u16 != 0 {
return crate::gen_errno!(libc::EINTR);
}
if nlh.nlmsg_type >= libc::NLMSG_MIN_TYPE as u16 {
if let Some(ref mut cb) = cb_data {
match cb(&nlh) {
Ok(CbStatus::Ok) => {}
ret @ _ => return ret,
}
}
} else if nlh.nlmsg_type < cb_ctl_array.len() as u16 {
if let Some(ref mut ctl_cb) = cb_ctl_array[nlh.nlmsg_type as usize] {
match ctl_cb(&nlh) {
Ok(CbStatus::Ok) => {}
ret @ _ => return ret,
}
}
} else if let Some(default_cb) = DEFAULT_CB_ARRAY[nlh.nlmsg_type as usize] {
match default_cb(&nlh) {
Ok(CbStatus::Ok) => {}
ret @ _ => return ret,
}
}
nlh = unsafe { nlh.next(&mut len) };
if !nlh.ok(len) {
break;
}
}
Ok(CbStatus::Ok)
}
pub fn run2<T, U>(
buf: &[u8],
seq: u32,
portid: u32,
cb_data: Option<T>,
cb_ctl_array: &mut [Option<U>],
) -> CbResult
where
T: FnMut(&Msghdr) -> CbResult,
U: FnMut(&Msghdr) -> CbResult,
{
__run(buf, seq, portid, cb_data, cb_ctl_array)
}
pub fn run<U: FnMut(&Msghdr) -> CbResult>(
buf: &[u8],
seq: u32,
portid: u32,
cb_data: Option<U>,
) -> CbResult {
__run(buf, seq, portid, cb_data, &mut [] as &mut [Option<U>])
}