use crate::mnl::nlmsg::{Header, Message};
use libc::{EINTR, EPROTO, ESRCH};
use std::ptr::null_mut;
pub type callback_t = *mut fn(nlh: *const Header, data: *mut u8) -> i32;
pub struct Callback {}
impl Callback {
pub const OK: i32 = 1;
pub const STOP: i32 = 2;
pub const ERROR: i32 = 3;
pub const fn noop(_nlh: *const Header, _data: *mut u8) -> i32 {
Self::OK
}
pub fn error(nlh: *const Header, _data: *mut u8) -> i32 {
unsafe {
let err = *(nlh.add(1) as *const i32);
if err < 0 {
return -err;
} else {
if (err as u32) & Message::DUMP_INTR != 0 {
return -EINTR;
}
}
if err == 0 { Self::STOP } else { -err }
}
}
pub const fn stop(_nlh: *const Header, _data: *mut u8) -> i32 {
Self::STOP
}
pub const default_array: [Option<callback_t>; Message::MIN_TYPE as usize] = {
let mut array: [Option<callback_t>; Message::MIN_TYPE as usize] =
[None; Message::MIN_TYPE as usize];
array[Message::NOOP as usize] = Some(Self::noop as callback_t);
array[Message::ERROR as usize] = Some(Self::error as callback_t);
array[Message::DONE as usize] = Some(Self::stop as callback_t);
array[Message::OVERRUN as usize] = Some(Self::noop as callback_t);
array
};
pub fn __run(
buf: *const u8,
numbytes: usize,
seq: u32,
portid: u32,
cb_data: callback_t,
data: *mut u8,
cb_ctl_array: *const callback_t,
cb_ctl_array_len: u32,
) -> i32 {
unsafe {
let mut ret: i32 = Self::OK;
let mut len: i32 = numbytes as i32;
let mut nlh = buf as *mut Header;
while (*nlh).is_ok(len) {
if !(*nlh).portid_ok(portid) {
return -ESRCH;
}
if !(*nlh).seq_ok(seq) {
return -EPROTO;
}
if ((*nlh).flags as u32 & Message::DUMP_INTR) != 0 {
return -EINTR;
}
if (*nlh).type_ >= Message::MIN_TYPE {
if !cb_data.is_null() {
ret = (*cb_data)(nlh, data);
if ret <= Self::STOP {
return ret;
}
}
} else if (*nlh).type_ < cb_ctl_array_len as u16 {
if !cb_ctl_array.is_null() {
let cb = *cb_ctl_array.add((*nlh).type_ as usize);
if !cb.is_null() {
ret = (*cb)(nlh, data);
if ret <= Self::STOP {
return ret;
}
}
}
} else if let Some(cb) = Self::default_array[(*nlh).type_ as usize] {
ret = (*cb)(nlh, data);
if ret <= Self::STOP {
return ret;
}
}
nlh = (*nlh).next(&mut len);
}
ret
}
}
pub fn run2(
buf: *const u8,
numbytes: usize,
seq: u32,
portid: u32,
cb_data: callback_t,
data: *mut u8,
cb_ctl_array: *const callback_t,
cb_ctl_array_len: u32,
) -> i32 {
Self::__run(
buf,
numbytes,
seq,
portid,
cb_data,
data,
cb_ctl_array,
cb_ctl_array_len,
)
}
pub fn run(
buf: *const u8,
numbytes: usize,
seq: u32,
portid: u32,
cb_data: callback_t,
data: *mut u8,
) -> i32 {
Self::__run(buf, numbytes, seq, portid, cb_data, data, null_mut(), 0)
}
}