use std::{
convert::{AsRef, Into},
marker::PhantomData,
mem, slice,
};
use errno::Errno;
use libc;
use {Attr, Msghdr, Result};
pub struct MsgVec {
buf: Vec<u8>,
nlmsg_len: isize, nest_nla: Vec<isize>, }
#[repr(C)]
pub struct Header<'a> {
_nlmsg_len: u32, pub nlmsg_type: u16,
pub nlmsg_flags: u16,
pub nlmsg_seq: u32,
pub nlmsg_pid: u32,
_buf: PhantomData<&'a mut MsgVec>,
}
impl AsRef<[u8]> for MsgVec {
fn as_ref(&self) -> &[u8] {
&self.buf.as_ref()
}
}
impl MsgVec {
pub fn new() -> Self {
Self {
buf: Vec::with_capacity(crate::socket_buffer_size()),
nlmsg_len: -1,
nest_nla: Vec::new(),
}
}
pub fn with_capacity(size: usize) -> Self {
Self {
buf: Vec::with_capacity(size),
nlmsg_len: -1,
nest_nla: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn capacity(&self) -> usize {
self.buf.capacity()
}
pub fn nlmsg_len(&self) -> u32 {
if self.nlmsg_len < 0 {
0
} else {
unsafe { *(self.buf.as_ptr().offset(self.nlmsg_len) as *const _ as *const u32) }
}
}
pub fn reset(&mut self) {
self.buf.clear();
self.nlmsg_len = -1;
}
pub fn put_header(&mut self) -> &mut Header {
let old_len = self.buf.len();
let new_len = old_len + Msghdr::HDRLEN as usize;
self.buf.reserve(new_len);
let ret = unsafe {
self.buf.set_len(new_len);
self.buf[old_len..new_len]
.iter_mut()
.map(|x| *x = 0)
.count();
let ptr = self.buf.as_mut_ptr().offset(old_len as isize) as *mut _ as *mut Header;
(*ptr)._nlmsg_len = Msghdr::HDRLEN as u32;
self.nlmsg_len = old_len as isize;
&mut *ptr
};
ret
}
fn extends<T>(&mut self, size: usize) -> Result<&mut T> {
if self.nlmsg_len < 0 {
return Err(Errno(libc::EBADMSG));
}
let old_len = self.buf.len();
let new_len = old_len + crate::align(size);
unsafe {
let nlmsg_len = self.buf.as_mut_ptr().offset(self.nlmsg_len) as *mut _ as *mut u32;
*nlmsg_len += crate::align(size) as u32;
}
self.buf.reserve(new_len);
unsafe {
self.buf.set_len(new_len);
self.buf[old_len..new_len]
.iter_mut()
.map(|x| *x = 0)
.count();
Ok(&mut *(self.buf.as_mut_ptr().offset(old_len as isize) as *mut _ as *mut T))
}
}
pub fn put_extra_header<T>(&mut self) -> Result<&mut T> {
let ptr = self.extends::<T>(mem::size_of::<T>())?;
Ok(unsafe { &mut *(ptr as *mut T) })
}
pub fn put<T: Sized + Into<u16>, U: Copy>(&mut self, atype: T, data: &U) -> Result<&mut Self> {
let attr_len = Attr::HDRLEN as u16 + mem::size_of::<U>() as u16;
let attr = self.extends::<Attr>(attr_len as usize)?;
attr.nla_type = atype.into();
attr.nla_len = attr_len;
let dst = unsafe { attr.payload_raw_mut::<U>() };
*dst = *data;
Ok(self)
}
fn _put_bytes<T: Sized + Into<u16>>(
&mut self,
atype: T,
data: &[u8],
len: usize,
) -> Result<&mut Self> {
let attr_len = (Attr::HDRLEN + len) as u16;
let attr = self.extends::<Attr>(attr_len as usize)?;
attr.nla_type = atype.into();
attr.nla_len = attr_len;
let src = data as *const _ as *const u8;
let dst = unsafe { attr.payload_raw_mut::<u8>() };
for i in 0..data.len() {
unsafe {
*(dst as *mut u8).offset(i as isize) = *src.offset(i as isize);
}
}
Ok(self)
}
pub fn put_bytes<T: Sized + Into<u16>>(&mut self, atype: T, data: &[u8]) -> Result<&mut Self> {
self._put_bytes(atype, data, data.len())
}
pub fn put_str<T: Sized + Into<u16>>(&mut self, atype: T, data: &str) -> Result<&mut Self> {
self.put_bytes(atype, data.as_bytes())
}
pub fn put_cstr<T: Sized + Into<u16>>(&mut self, atype: T, data: &str) -> Result<&mut Self> {
let b = data.as_bytes();
self._put_bytes(atype, b, b.len() + 1)
}
pub fn put_flag<T: Sized + Into<u16>>(&mut self, atype: T) -> Result<&mut Self> {
let attr = self.extends::<Attr>(Attr::HDRLEN as usize)?;
attr.nla_type = atype.into();
attr.nla_len = Attr::HDRLEN as u16;
Ok(self)
}
pub fn nest_start<T: Sized + Into<u16>>(&mut self, atype: T) -> Result<&mut Self> {
let bufptr = self.buf.as_ptr();
let start = self.extends::<Attr>(Attr::HDRLEN as usize)?;
let offset = start as *const _ as isize - bufptr as isize;
start.nla_type = libc::NLA_F_NESTED as u16 | atype.into();
self.nest_nla.push(offset);
Ok(self)
}
pub fn nest_end(&mut self) -> Result<&mut Self> {
let len = self.buf.len() as isize;
let offset = self.nest_nla.pop().ok_or(Errno(libc::EINVAL))?;
if offset + Attr::HDRLEN as isize > len {
self.nest_nla.push(offset);
return Err(Errno(libc::EINVAL));
}
unsafe {
let start = self.buf.as_mut_ptr().offset(offset) as *mut _ as *mut u16;
*start = (len - offset) as u16
};
Ok(self)
}
pub fn nest_cancel(&mut self) -> Result<&mut Self> {
if self.nlmsg_len < 0 {
return Err(Errno(libc::EBADMSG));
}
let len = self.buf.len() as isize;
let offset = self.nest_nla.pop().ok_or(Errno(libc::EINVAL))?;
if offset > len {
self.nest_nla.push(offset);
return Err(Errno(libc::EINVAL));
}
unsafe {
let nlmsg_len = self.buf.as_mut_ptr().offset(self.nlmsg_len) as *mut _ as *mut u32;
*nlmsg_len -= (len - offset) as u32;
self.buf.set_len(offset as usize);
}
Ok(self)
}
pub fn nest_depth(&self) -> usize {
self.nest_nla.len()
}
pub fn header(&self) -> Result<&Header> {
if self.nlmsg_len < 0 {
Err(Errno(libc::EBADMSG))
} else {
Ok(
unsafe {
&*(self.buf.as_ptr().offset(self.nlmsg_len) as *const _ as *const Header)
},
)
}
}
pub fn msghdr(&self) -> Result<&Msghdr> {
if self.nlmsg_len < 0 {
Err(Errno(libc::EBADMSG))
} else {
Ok(
unsafe {
&*(self.buf.as_ptr().offset(self.nlmsg_len) as *const _ as *const Msghdr)
},
)
}
}
}
impl<'a> Header<'a> {
pub fn nlmsg_len(&self) -> u32 {
self._nlmsg_len
}
}
impl<'a> AsRef<[u8]> for Header<'a> {
fn as_ref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self as *const _ as *const u8, self._nlmsg_len as usize) }
}
}