use crate as neli;
use std::io::Cursor;
use crate::{
attr::{AttrHandle, AttrHandleMut, Attribute},
consts::genl::{Cmd, NlAttrType},
err::{DeError, SerError},
types::{Buffer, GenlBuffer},
FromBytes, FromBytesWithInput, Header, Size, ToBytes, TypeSize,
};
#[derive(Debug, PartialEq, Eq, Size, ToBytes, FromBytes)]
pub struct NoUserHeader;
impl TypeSize for NoUserHeader {
fn type_size() -> usize {
0
}
}
#[derive(Debug, PartialEq, Eq, Size, ToBytes, FromBytesWithInput, Header)]
#[neli(to_bytes_bound = "C: Cmd")]
#[neli(to_bytes_bound = "T: NlAttrType")]
#[neli(from_bytes_bound = "C: Cmd + TypeSize")]
#[neli(from_bytes_bound = "T: NlAttrType")]
#[neli(header_bound = "C: TypeSize")]
#[neli(from_bytes_bound = "H: TypeSize + FromBytes")]
#[neli(header_bound = "H: TypeSize")]
pub struct Genlmsghdr<C, T, H = NoUserHeader> {
pub cmd: C,
pub version: u8,
reserved: u16,
pub header: H,
#[neli(input = "input - Self::header_size()")]
attrs: GenlBuffer<T, Buffer>,
}
impl<C, T> Genlmsghdr<C, T>
where
C: Cmd,
T: NlAttrType,
{
pub fn new(cmd: C, version: u8, attrs: GenlBuffer<T, Buffer>) -> Self {
Genlmsghdr {
cmd,
version,
reserved: 0,
header: NoUserHeader,
attrs,
}
}
pub fn get_attr_handle(&self) -> AttrHandle<GenlBuffer<T, Buffer>, Nlattr<T, Buffer>> {
self.attrs.get_attr_handle()
}
pub fn get_attr_handle_mut(
&mut self,
) -> AttrHandleMut<GenlBuffer<T, Buffer>, Nlattr<T, Buffer>> {
self.attrs.get_attr_handle_mut()
}
}
impl<C, T, H> Genlmsghdr<C, T, H> {
pub fn new_with_user_header(
cmd: C,
version: u8,
header: H,
attrs: GenlBuffer<T, Buffer>,
) -> Self {
Genlmsghdr {
cmd,
version,
reserved: 0,
header,
attrs,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct AttrType<T> {
pub nla_nested: bool,
pub nla_network_order: bool,
pub nla_type: T,
}
impl<T> Size for AttrType<T>
where
T: Size,
{
fn unpadded_size(&self) -> usize {
self.nla_type.unpadded_size()
}
}
impl<T> TypeSize for AttrType<T>
where
T: TypeSize,
{
fn type_size() -> usize {
T::type_size()
}
}
impl<T> ToBytes for AttrType<T>
where
T: NlAttrType,
{
fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
let int: u16 = self.into();
int.to_bytes(buffer)
}
}
impl<'lt, T> FromBytes<'lt> for AttrType<T>
where
T: NlAttrType,
{
fn from_bytes(buffer: &mut Cursor<&'lt [u8]>) -> Result<Self, DeError> {
let int = u16::from_bytes(buffer)?;
Ok(AttrType::from(int))
}
}
impl<T> From<AttrType<T>> for u16
where
T: NlAttrType,
{
fn from(v: AttrType<T>) -> Self {
let mut int: u16 = v.nla_type.into();
int |= u16::from(v.nla_nested) << 15;
int |= u16::from(v.nla_network_order) << 14;
int
}
}
impl<'a, T> From<&'a AttrType<T>> for u16
where
T: NlAttrType,
{
fn from(v: &'a AttrType<T>) -> Self {
let mut int: u16 = v.nla_type.into();
int |= u16::from(v.nla_nested) << 15;
int |= u16::from(v.nla_network_order) << 14;
int
}
}
impl<T> From<u16> for AttrType<T>
where
T: NlAttrType,
{
fn from(int: u16) -> Self {
AttrType {
nla_nested: (int & 1 << 15) == (1 << 15),
nla_network_order: (int & 1 << 14) == (1 << 14),
nla_type: T::from(!(3 << 14) & int),
}
}
}
#[derive(Debug, PartialEq, Eq, Size, FromBytes, ToBytes, Header)]
#[neli(from_bytes_bound = "T: NlAttrType")]
#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
#[neli(to_bytes_bound = "T: NlAttrType")]
#[neli(header_bound = "T: TypeSize")]
#[neli(padding)]
pub struct Nlattr<T, P> {
pub nla_len: u16,
pub nla_type: AttrType<T>,
#[neli(input = "nla_len as usize - Self::header_size()")]
pub nla_payload: P,
}
impl<T> Nlattr<T, Buffer>
where
T: NlAttrType,
{
pub fn new<P>(
nla_nested: bool,
nla_network_order: bool,
nla_type: T,
nla_payload: P,
) -> Result<Self, SerError>
where
P: Size + ToBytes,
{
let mut attr = Nlattr {
nla_len: Self::header_size() as u16,
nla_type: AttrType {
nla_nested,
nla_network_order,
nla_type,
},
nla_payload: Buffer::new(),
};
attr.set_payload(&nla_payload)?;
Ok(attr)
}
pub fn add_nested_attribute<TT, P>(&mut self, attr: &Nlattr<TT, P>) -> Result<(), SerError>
where
TT: NlAttrType,
P: ToBytes,
{
let mut buffer = Cursor::new(Vec::new());
attr.to_bytes(&mut buffer)?;
self.nla_payload.extend_from_slice(buffer.get_ref());
self.nla_len += buffer.get_ref().len() as u16;
Ok(())
}
pub fn get_attr_handle<R>(&self) -> Result<GenlAttrHandle<R>, DeError>
where
R: NlAttrType,
{
Ok(AttrHandle::new(GenlBuffer::from_bytes_with_input(
&mut Cursor::new(self.nla_payload.as_ref()),
self.nla_payload.unpadded_size(),
)?))
}
pub fn get_attr_handle_mut<R>(&mut self) -> Result<GenlAttrHandleMut<R>, DeError>
where
R: NlAttrType,
{
Ok(AttrHandleMut::new(GenlBuffer::from_bytes_with_input(
&mut Cursor::new(self.nla_payload.as_ref()),
self.nla_payload.unpadded_size(),
)?))
}
}
impl<T> Attribute<T> for Nlattr<T, Buffer>
where
T: NlAttrType,
{
fn payload(&self) -> &Buffer {
&self.nla_payload
}
fn set_payload<P>(&mut self, payload: &P) -> Result<(), SerError>
where
P: Size + ToBytes,
{
let mut buffer = Cursor::new(Vec::new());
payload.to_bytes(&mut buffer)?;
self.nla_len -= self.nla_payload.unpadded_size() as u16;
self.nla_len += buffer.get_ref().len() as u16;
self.nla_payload = Buffer::from(buffer.into_inner());
Ok(())
}
}
type GenlAttrHandle<'a, T> = AttrHandle<'a, GenlBuffer<T, Buffer>, Nlattr<T, Buffer>>;
type GenlAttrHandleMut<'a, T> = AttrHandleMut<'a, GenlBuffer<T, Buffer>, Nlattr<T, Buffer>>;
impl<'a, T> AttrHandle<'a, GenlBuffer<T, Buffer>, Nlattr<T, Buffer>>
where
T: NlAttrType,
{
pub fn get_nested_attributes<S>(&mut self, subattr: T) -> Result<GenlAttrHandle<S>, DeError>
where
S: NlAttrType,
{
let attr = self
.get_attribute(subattr)
.ok_or_else(|| DeError::new("Couldn't find specified attribute"))?;
Ok(AttrHandle::new(GenlBuffer::from_bytes_with_input(
&mut Cursor::new(attr.nla_payload.as_ref()),
attr.nla_payload.unpadded_size(),
)?))
}
pub fn get_attribute(&self, t: T) -> Option<&Nlattr<T, Buffer>> {
self.get_attrs()
.iter()
.find(|item| item.nla_type.nla_type == t)
}
pub fn get_attr_payload_as<'b, R>(&'b self, attr: T) -> Result<R, DeError>
where
R: FromBytes<'b>,
{
match self.get_attribute(attr) {
Some(a) => a.get_payload_as::<R>(),
_ => Err(DeError::new("Failed to find specified attribute")),
}
}
pub fn get_attr_payload_as_with_len<'b, R>(&'b self, attr: T) -> Result<R, DeError>
where
R: FromBytesWithInput<'b, Input = usize>,
{
match self.get_attribute(attr) {
Some(a) => a.get_payload_as_with_len::<R>(),
_ => Err(DeError::new("Failed to find specified attribute")),
}
}
}