neli/
types.rs

1//! Module containing various types used across the various netlink
2//! structures used in `neli`.
3//!
4//! # Design decisions
5//! These structures are new types rather than type aliases in most
6//! cases to allow the internal representation to change without
7//! resulting in a breaking change.
8
9use std::{
10    fmt::{self, Debug},
11    io::{Read, Write},
12    iter::FromIterator,
13    slice::{Iter, IterMut},
14};
15
16use crate::{
17    self as neli, FromBytesWithInput, Size, ToBytes,
18    attr::AttrHandle,
19    consts::{genl::NlAttrType, nl::NlType, rtnl::RtaType},
20    err::DeError,
21    genl::{AttrTypeBuilder, GenlAttrHandle, Nlattr, NlattrBuilder},
22    nl::Nlmsghdr,
23    rtnl::{RtAttrHandle, Rtattr},
24};
25
26/// A buffer of bytes.
27#[derive(Clone, PartialEq, Eq, Size)]
28pub struct Buffer(Vec<u8>);
29
30impl FromBytesWithInput for Buffer {
31    type Input = usize;
32
33    fn from_bytes_with_input(
34        buffer: &mut std::io::Cursor<impl AsRef<[u8]>>,
35        input: Self::Input,
36    ) -> Result<Self, DeError> {
37        if buffer.position() as usize + input > buffer.get_ref().as_ref().len() {
38            return Err(DeError::InvalidInput(input));
39        }
40
41        let mut vec = vec![0u8; input];
42
43        buffer.read_exact(&mut vec)?;
44
45        Ok(Self::from(vec))
46    }
47}
48
49impl ToBytes for Buffer {
50    fn to_bytes(&self, buffer: &mut std::io::Cursor<Vec<u8>>) -> Result<(), crate::err::SerError> {
51        buffer.write_all(self.0.as_slice())?;
52        Ok(())
53    }
54}
55
56impl Debug for Buffer {
57    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58        write!(f, "Buffer")
59    }
60}
61
62impl AsRef<[u8]> for Buffer {
63    fn as_ref(&self) -> &[u8] {
64        self.0.as_slice()
65    }
66}
67
68impl AsMut<[u8]> for Buffer {
69    fn as_mut(&mut self) -> &mut [u8] {
70        self.0.as_mut_slice()
71    }
72}
73
74impl<'a> From<&'a [u8]> for Buffer {
75    fn from(slice: &'a [u8]) -> Self {
76        Buffer(Vec::from(slice))
77    }
78}
79
80impl From<Vec<u8>> for Buffer {
81    fn from(vec: Vec<u8>) -> Self {
82        Buffer(vec)
83    }
84}
85
86impl From<Buffer> for Vec<u8> {
87    fn from(buf: Buffer) -> Self {
88        buf.0
89    }
90}
91
92impl Buffer {
93    /// Create a new general purpose byte buffer.
94    pub fn new() -> Self {
95        Buffer(Vec::new())
96    }
97
98    /// Extend the given buffer with the contents of another slice.
99    pub fn extend_from_slice(&mut self, slice: &[u8]) {
100        self.0.extend_from_slice(slice)
101    }
102
103    /// Get the current length of the buffer.
104    pub fn len(&self) -> usize {
105        self.0.len()
106    }
107
108    /// Check whether the buffer is empty.
109    pub fn is_empty(&self) -> bool {
110        self.0.is_empty()
111    }
112}
113
114impl Default for Buffer {
115    fn default() -> Self {
116        Self::new()
117    }
118}
119
120/// A buffer of netlink messages.
121#[derive(Debug, PartialEq, Eq, Size, FromBytesWithInput, ToBytes)]
122#[neli(from_bytes_bound = "T: NlType")]
123#[neli(from_bytes_bound = "P: Size + FromBytesWithInput<Input = usize>")]
124pub struct NlBuffer<T, P>(#[neli(input)] Vec<Nlmsghdr<T, P>>);
125
126impl<T, P> FromIterator<Nlmsghdr<T, P>> for NlBuffer<T, P> {
127    fn from_iter<I>(i: I) -> Self
128    where
129        I: IntoIterator<Item = Nlmsghdr<T, P>>,
130    {
131        NlBuffer(Vec::from_iter(i))
132    }
133}
134
135impl<T, P> AsRef<[Nlmsghdr<T, P>]> for NlBuffer<T, P> {
136    fn as_ref(&self) -> &[Nlmsghdr<T, P>] {
137        self.0.as_slice()
138    }
139}
140
141impl<T, P> NlBuffer<T, P> {
142    /// Create a new buffer of netlink messages.
143    pub fn new() -> Self {
144        NlBuffer(Vec::new())
145    }
146
147    /// Add a new netlink message to the end of the buffer.
148    pub fn push(&mut self, msg: Nlmsghdr<T, P>) {
149        self.0.push(msg);
150    }
151
152    /// Get a netlink message from the end of the buffer.
153    pub fn pop(&mut self) -> Option<Nlmsghdr<T, P>> {
154        self.0.pop()
155    }
156
157    /// Return an iterator over immutable references to the elements
158    /// in the buffer.
159    pub fn iter(&self) -> Iter<'_, Nlmsghdr<T, P>> {
160        self.0.iter()
161    }
162
163    /// Return an iterator over mutable references to the elements
164    /// in the buffer.
165    pub fn iter_mut(&mut self) -> IterMut<'_, Nlmsghdr<T, P>> {
166        self.0.iter_mut()
167    }
168
169    /// Returns the number of elements in the buffer.
170    pub fn len(&self) -> usize {
171        self.0.len()
172    }
173
174    /// Returns whether the number of elements in the buffer is 0.
175    pub fn is_empty(&self) -> bool {
176        self.0.is_empty()
177    }
178}
179
180impl<T, P> IntoIterator for NlBuffer<T, P> {
181    type Item = Nlmsghdr<T, P>;
182    type IntoIter = <Vec<Nlmsghdr<T, P>> as IntoIterator>::IntoIter;
183
184    fn into_iter(self) -> Self::IntoIter {
185        self.0.into_iter()
186    }
187}
188
189impl<T, P> Default for NlBuffer<T, P> {
190    fn default() -> Self {
191        Self::new()
192    }
193}
194
195/// A buffer of generic netlink attributes.
196#[derive(Clone, Debug, PartialEq, Eq, ToBytes, FromBytesWithInput)]
197#[neli(to_bytes_bound = "T: NlAttrType")]
198#[neli(from_bytes_bound = "T: NlAttrType")]
199#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
200pub struct GenlBuffer<T, P>(#[neli(input)] Vec<Nlattr<T, P>>);
201
202impl<T, P> neli::Size for GenlBuffer<T, P>
203where
204    T: Size,
205    P: Size,
206{
207    fn unpadded_size(&self) -> usize {
208        self.0.iter().map(|attr| attr.padded_size()).sum()
209    }
210}
211
212impl<T> GenlBuffer<T, Buffer> {
213    /// Get a data structure with an immutable reference to the
214    /// underlying [`Nlattr`]s.
215    pub fn get_attr_handle(&self) -> AttrHandle<Self, Nlattr<T, Buffer>> {
216        AttrHandle::new_borrowed(self.0.as_ref())
217    }
218}
219
220impl GenlBuffer<u16, Buffer> {
221    /// Convert a [`GenlBuffer`] that can represent all types to a buffer that
222    /// is of a particular type.
223    pub fn get_typed_attr_handle<T>(&self) -> Result<GenlAttrHandle<T>, DeError>
224    where
225        T: NlAttrType,
226    {
227        Ok(AttrHandle::new({
228            let mut attrs = GenlBuffer::new();
229            for attr in self.0.iter() {
230                attrs.push(
231                    NlattrBuilder::default()
232                        .nla_type(
233                            AttrTypeBuilder::default()
234                                .nla_type(T::from(*attr.nla_type().nla_type()))
235                                .nla_nested(*attr.nla_type().nla_nested())
236                                .nla_network_order(*attr.nla_type().nla_network_order())
237                                .build()?,
238                        )
239                        .nla_payload(attr.nla_payload().clone())
240                        .build()?,
241                );
242            }
243            attrs
244        }))
245    }
246}
247
248impl<T, P> AsRef<[Nlattr<T, P>]> for GenlBuffer<T, P> {
249    fn as_ref(&self) -> &[Nlattr<T, P>] {
250        self.0.as_slice()
251    }
252}
253
254impl<T, P> AsMut<[Nlattr<T, P>]> for GenlBuffer<T, P> {
255    fn as_mut(&mut self) -> &mut [Nlattr<T, P>] {
256        self.0.as_mut_slice()
257    }
258}
259
260impl<T, P> FromIterator<Nlattr<T, P>> for GenlBuffer<T, P> {
261    fn from_iter<I>(i: I) -> Self
262    where
263        I: IntoIterator<Item = Nlattr<T, P>>,
264    {
265        GenlBuffer(Vec::from_iter(i))
266    }
267}
268
269impl<T, P> IntoIterator for GenlBuffer<T, P> {
270    type Item = Nlattr<T, P>;
271    type IntoIter = <Vec<Nlattr<T, P>> as IntoIterator>::IntoIter;
272
273    fn into_iter(self) -> Self::IntoIter {
274        self.0.into_iter()
275    }
276}
277
278impl<T, P> GenlBuffer<T, P> {
279    /// Create a new buffer of generic netlink attributes.
280    pub fn new() -> Self {
281        GenlBuffer(Vec::new())
282    }
283
284    /// Add a new generic netlink attribute to the end of the buffer.
285    pub fn push(&mut self, attr: Nlattr<T, P>) {
286        self.0.push(attr)
287    }
288
289    /// Get a generic netlink attribute from the end of the buffer.
290    pub fn pop(&mut self) -> Option<Nlattr<T, P>> {
291        self.0.pop()
292    }
293
294    /// Return an iterator over immutable references to the elements
295    /// in the buffer.
296    pub fn iter(&self) -> Iter<'_, Nlattr<T, P>> {
297        self.0.iter()
298    }
299
300    /// Return an iterator over mutable references to the elements
301    /// in the buffer.
302    pub fn iter_mut(&mut self) -> IterMut<'_, Nlattr<T, P>> {
303        self.0.iter_mut()
304    }
305
306    /// Returns the number of elements in the buffer.
307    pub fn len(&self) -> usize {
308        self.0.len()
309    }
310
311    /// Returns whether the number of elements in the buffer is 0.
312    pub fn is_empty(&self) -> bool {
313        self.0.is_empty()
314    }
315}
316
317impl<T, P> Default for GenlBuffer<T, P> {
318    fn default() -> Self {
319        Self::new()
320    }
321}
322
323/// A buffer of rtnetlink attributes.
324#[derive(Clone, Debug, FromBytesWithInput, ToBytes)]
325#[neli(from_bytes_bound = "T: RtaType")]
326#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
327pub struct RtBuffer<T, P>(#[neli(input)] Vec<Rtattr<T, P>>);
328
329impl<T, P> neli::Size for RtBuffer<T, P>
330where
331    T: Size,
332    P: Size,
333{
334    fn unpadded_size(&self) -> usize {
335        self.0.iter().map(|attr| attr.padded_size()).sum()
336    }
337}
338
339impl<T> RtBuffer<T, Buffer> {
340    /// Get a data structure with an immutable reference to the
341    /// underlying [`Rtattr`]s.
342    pub fn get_attr_handle(&self) -> RtAttrHandle<T> {
343        AttrHandle::new_borrowed(self.0.as_ref())
344    }
345}
346
347impl<T, P> FromIterator<Rtattr<T, P>> for RtBuffer<T, P> {
348    fn from_iter<I>(i: I) -> Self
349    where
350        I: IntoIterator<Item = Rtattr<T, P>>,
351    {
352        RtBuffer(Vec::from_iter(i))
353    }
354}
355
356impl<T, P> IntoIterator for RtBuffer<T, P> {
357    type Item = Rtattr<T, P>;
358    type IntoIter = <Vec<Rtattr<T, P>> as IntoIterator>::IntoIter;
359
360    fn into_iter(self) -> Self::IntoIter {
361        self.0.into_iter()
362    }
363}
364
365impl<T, P> AsRef<[Rtattr<T, P>]> for RtBuffer<T, P> {
366    fn as_ref(&self) -> &[Rtattr<T, P>] {
367        self.0.as_slice()
368    }
369}
370
371impl<T, P> AsMut<[Rtattr<T, P>]> for RtBuffer<T, P> {
372    fn as_mut(&mut self) -> &mut [Rtattr<T, P>] {
373        self.0.as_mut_slice()
374    }
375}
376
377impl<T, P> RtBuffer<T, P> {
378    /// Create a new buffer of routing netlink attributes.
379    pub fn new() -> Self {
380        RtBuffer(Vec::new())
381    }
382
383    /// Add a new routing netlink attribute to the end of the buffer.
384    pub fn push(&mut self, attr: Rtattr<T, P>) {
385        self.0.push(attr)
386    }
387
388    /// Get a routing netlink attribute from the end of the buffer.
389    pub fn pop(&mut self) -> Option<Rtattr<T, P>> {
390        self.0.pop()
391    }
392
393    /// Return an iterator over immutable references to the elements
394    /// in the buffer.
395    pub fn iter(&self) -> Iter<'_, Rtattr<T, P>> {
396        self.0.iter()
397    }
398
399    /// Return an iterator over mutable references to the elements
400    /// in the buffer.
401    pub fn iter_mut(&mut self) -> IterMut<'_, Rtattr<T, P>> {
402        self.0.iter_mut()
403    }
404
405    /// Returns the number of elements in the buffer.
406    pub fn len(&self) -> usize {
407        self.0.len()
408    }
409
410    /// Returns whether the number of elements in the buffer is 0.
411    pub fn is_empty(&self) -> bool {
412        self.0.is_empty()
413    }
414}
415
416impl<T, P> Default for RtBuffer<T, P> {
417    fn default() -> Self {
418        Self::new()
419    }
420}
421
422#[cfg(test)]
423mod test {
424    use super::*;
425
426    use crate::{
427        consts::{genl::Index, rtnl::Ifa},
428        genl::{AttrTypeBuilder, NlattrBuilder},
429        rtnl::RtattrBuilder,
430    };
431
432    #[test]
433    fn test_genlbuffer_align() {
434        assert_eq!(
435            vec![
436                NlattrBuilder::default()
437                    .nla_type(
438                        AttrTypeBuilder::default()
439                            .nla_type(Index::from(0))
440                            .build()
441                            .unwrap(),
442                    )
443                    .nla_payload(0u8)
444                    .build()
445                    .unwrap(),
446                NlattrBuilder::default()
447                    .nla_type(
448                        AttrTypeBuilder::default()
449                            .nla_type(Index::from(1))
450                            .build()
451                            .unwrap(),
452                    )
453                    .nla_payload(1u8)
454                    .build()
455                    .unwrap(),
456                NlattrBuilder::default()
457                    .nla_type(
458                        AttrTypeBuilder::default()
459                            .nla_type(Index::from(2))
460                            .build()
461                            .unwrap(),
462                    )
463                    .nla_payload(2u8)
464                    .build()
465                    .unwrap(),
466            ]
467            .into_iter()
468            .collect::<GenlBuffer<Index, Buffer>>()
469            .unpadded_size(),
470            24
471        )
472    }
473
474    #[test]
475    fn test_rtbuffer_align() {
476        assert_eq!(
477            vec![
478                RtattrBuilder::default()
479                    .rta_type(Ifa::Unspec)
480                    .rta_payload(0u8)
481                    .build()
482                    .unwrap(),
483                RtattrBuilder::default()
484                    .rta_type(Ifa::Address)
485                    .rta_payload(1u8)
486                    .build()
487                    .unwrap(),
488                RtattrBuilder::default()
489                    .rta_type(Ifa::Local)
490                    .rta_payload(2u8)
491                    .build()
492                    .unwrap(),
493            ]
494            .into_iter()
495            .collect::<RtBuffer<Ifa, Buffer>>()
496            .unpadded_size(),
497            24
498        )
499    }
500}