netlink_bindings/
utils.rs

1use std::fmt;
2
3pub use crate::primitives::*;
4pub use std::{ffi::CStr, fmt::Debug, iter::Iterator};
5
6pub fn dump_hex(buf: &[u8]) {
7    let mut len = 0;
8    for chunk in buf.chunks(16) {
9        print!("{len:04x?}: ");
10        print!("{chunk:02x?} ");
11        for b in chunk {
12            if b.is_ascii() && !b.is_ascii_control() {
13                print!("{}", char::from_u32(*b as u32).unwrap());
14            } else {
15                print!(".");
16            }
17        }
18        println!(".");
19        len += chunk.len();
20    }
21}
22
23pub fn dump_assert_eq(left: &[u8], right: &[u8]) {
24    if left.len() != right.len() {
25        dump_hex(left);
26        dump_hex(right);
27        panic!("Length mismatched");
28    }
29    if let Some(pos) = left.iter().zip(right.iter()).position(|(l, r)| *l != *r) {
30        println!();
31        println!("Left:");
32        dump_hex(left);
33        println!();
34        println!("Right:");
35        dump_hex(right);
36        panic!("Differ at byte {pos} (0x{pos:x?})");
37    }
38}
39
40pub struct FormatHex<'a>(pub &'a [u8]);
41
42impl Debug for FormatHex<'_> {
43    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
44        write!(fmt, "\"")?;
45        for i in self.0 {
46            write!(fmt, "{i:02x}")?
47        }
48        write!(fmt, "\"")?;
49        Ok(())
50    }
51}
52
53pub struct FormatEnum<T: Debug>(pub u64, pub fn(u64) -> Option<T>);
54
55impl<T: Debug> Debug for FormatEnum<T> {
56    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
57        write!(fmt, "{} ", self.0)?;
58
59        if let Some(var) = (self.1)(self.0) {
60            write!(fmt, "[{var:?}]")?;
61        } else {
62            write!(fmt, "(unknown variant)")?;
63        }
64
65        Ok(())
66    }
67}
68
69pub struct FormatFlags<T: Debug>(pub u64, pub fn(u64) -> Option<T>);
70
71impl<T: Debug> Debug for FormatFlags<T> {
72    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(fmt, "{} ", self.0)?;
74
75        if self.0 == 0 {
76            write!(fmt, "(empty)")?;
77            return Ok(());
78        }
79
80        let mut seen_variant = false;
81        for i in 0..u64::BITS {
82            let bit = self.0 & (1 << i);
83            if bit == 0 {
84                continue;
85            }
86
87            if !seen_variant {
88                seen_variant = true;
89                write!(fmt, "[")?;
90            } else {
91                write!(fmt, ",")?;
92            }
93
94            if let Some(var) = (self.1)(bit) {
95                write!(fmt, "{var:?}")?;
96            } else {
97                write!(fmt, "(unknown bit {i})")?;
98            }
99        }
100
101        if seen_variant {
102            write!(fmt, "]")?;
103        }
104
105        Ok(())
106    }
107}
108
109pub struct DisplayAsDebug<T>(T);
110
111impl<T: fmt::Display> fmt::Debug for DisplayAsDebug<T> {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(f, "{}", self.0)
114    }
115}
116
117pub struct FlattenErrorContext<T: fmt::Debug>(pub Result<T, ErrorContext>);
118
119impl<T: Debug> fmt::Debug for FlattenErrorContext<T> {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        match &self.0 {
122            Ok(ok) => ok.fmt(f),
123            Err(err) => {
124                f.write_str("Err(")?;
125                err.fmt(f)?;
126                f.write_str(")")
127            }
128        }
129    }
130}
131
132pub const NLA_F_NESTED: u16 = 1 << 15;
133pub const NLA_F_NET_BYTEORDER: u16 = 1 << 14;
134
135pub const fn nla_type(r#type: u16) -> u16 {
136    r#type & (!(NLA_F_NESTED | NLA_F_NET_BYTEORDER))
137}
138
139pub const NLA_ALIGNTO: usize = 4;
140
141pub const fn nla_align_up(len: usize) -> usize {
142    ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
143}
144
145pub fn align(buf: &mut Vec<u8>) {
146    let len = buf.len();
147    buf.extend(std::iter::repeat_n(0u8, nla_align_up(len) - len));
148}
149
150/// Returns header offset
151pub fn push_nested_header(buf: &mut Vec<u8>, r#type: u16) -> usize {
152    push_header_type(buf, r#type, 0, true)
153}
154
155/// Returns header offset
156pub fn push_header(buf: &mut Vec<u8>, r#type: u16, len: u16) -> usize {
157    push_header_type(buf, r#type, len, false)
158}
159
160/// Returns header offset
161/// The kernel doesn't really check byteorder bit nor set it correctly
162fn push_header_type(buf: &mut Vec<u8>, mut r#type: u16, len: u16, is_nested: bool) -> usize {
163    align(buf);
164
165    let header_offset = buf.len();
166
167    if is_nested {
168        r#type |= NLA_F_NESTED;
169    }
170
171    // TODO: alignment for 8 byte types?
172    buf.extend((len + 4).to_ne_bytes());
173    buf.extend(r#type.to_ne_bytes());
174
175    align(buf);
176
177    header_offset
178}
179
180pub fn finalize_nested_header(buf: &mut Vec<u8>, offset: usize) {
181    align(buf);
182
183    let len = (buf.len() - offset) as u16;
184    buf[offset..(offset + 2)].copy_from_slice(&len.to_ne_bytes());
185}
186
187#[derive(Debug, Clone, Copy)]
188pub struct Header {
189    pub r#type: u16,
190    pub is_nested: bool,
191}
192
193pub fn chop_header<'a>(buf: &'a [u8], pos: &mut usize) -> Option<(Header, &'a [u8])> {
194    let buf = &buf[*pos..];
195
196    if buf.len() < 4 {
197        return None;
198    }
199
200    let len = parse_u16(&buf[0..2]).unwrap();
201    let r#type = parse_u16(&buf[2..4]).unwrap();
202
203    let next_len = nla_align_up(len as usize);
204
205    if len < 4 || buf.len() < len as usize {
206        return None;
207    }
208
209    let next = &buf[4..len as usize];
210    *pos += next_len.min(buf.len());
211
212    Some((
213        Header {
214            r#type: nla_type(r#type),
215            is_nested: r#type & NLA_F_NESTED != 0,
216        },
217        next,
218    ))
219}
220
221pub trait Rec {
222    fn as_rec_mut(&mut self) -> &mut Vec<u8>;
223}
224
225impl Rec for &mut Vec<u8> {
226    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
227        self
228    }
229}
230
231#[derive(Debug, Clone, PartialEq, Eq)]
232pub enum ErrorReason {
233    /// Only used in `.get_<attr>()` methods
234    AttrMissing,
235    /// Value of the attribute can't be parsed
236    ParsingError,
237    /// Found attribute of type not mentioned in the specification
238    UnknownAttr,
239}
240
241#[derive(Clone, PartialEq, Eq)]
242pub struct ErrorContext {
243    pub attrs: &'static str,
244    pub attr: Option<&'static str>,
245    pub offset: usize,
246    pub reason: ErrorReason,
247}
248
249impl std::error::Error for ErrorContext {}
250
251impl From<ErrorContext> for std::io::Error {
252    fn from(value: ErrorContext) -> Self {
253        Self::other(value)
254    }
255}
256
257impl fmt::Debug for ErrorContext {
258    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259        f.debug_struct("ErrorContext")
260            .field("message", &DisplayAsDebug(&self))
261            .field("reason", &self.reason)
262            .field("attrs", &self.attrs)
263            .field("attr", &self.attr)
264            .field("offset", &self.offset)
265            .finish()
266    }
267}
268
269impl fmt::Display for ErrorContext {
270    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271        let attrs = self.attrs;
272        if matches!(self.reason, ErrorReason::AttrMissing) {
273            let attr = self.attr.unwrap();
274            write!(f, "Missing attribute {attr:?} in {attrs:?}")?;
275            return Ok(());
276        } else {
277            write!(f, "Error parsing ")?;
278            if let Some(attr) = self.attr {
279                write!(f, "attribute {attr:?} of {attrs:?}")?;
280            } else {
281                write!(f, "header of {attrs:?}")?;
282                if matches!(self.reason, ErrorReason::UnknownAttr) {
283                    write!(f, " (unknown attribute)")?;
284                }
285            }
286        }
287        write!(f, " at offset {}", self.offset)?;
288        Ok(())
289    }
290}
291
292impl ErrorContext {
293    #[cold]
294    pub(crate) fn new(
295        attrs: &'static str,
296        attr: Option<&'static str>,
297        orig_loc: usize,
298        loc: usize,
299    ) -> ErrorContext {
300        let ctx = ErrorContext {
301            attrs,
302            attr,
303            offset: Self::calc_offset(orig_loc, loc),
304            reason: if attr.is_some() {
305                ErrorReason::ParsingError
306            } else {
307                ErrorReason::UnknownAttr
308            },
309        };
310
311        if cfg!(test) {
312            panic!("{ctx}")
313        } else {
314            ctx
315        }
316    }
317
318    #[cold]
319    pub(crate) fn new_missing(
320        attrs: &'static str,
321        attr: &'static str,
322        orig_loc: usize,
323        loc: usize,
324    ) -> ErrorContext {
325        let ctx = ErrorContext {
326            attrs,
327            attr: Some(attr),
328            offset: Self::calc_offset(orig_loc, loc),
329            reason: ErrorReason::AttrMissing,
330        };
331
332        if cfg!(test) {
333            panic!("{ctx}")
334        } else {
335            ctx
336        }
337    }
338
339    pub(crate) fn calc_offset(orig_loc: usize, loc: usize) -> usize {
340        if orig_loc <= loc && loc - orig_loc <= u16::MAX as usize {
341            loc - orig_loc
342        } else {
343            0
344        }
345    }
346}
347
348#[derive(Clone)]
349pub struct MultiAttrIterable<I, T, V>
350where
351    I: Iterator<Item = Result<T, ErrorContext>>,
352{
353    pub(crate) inner: I,
354    pub(crate) f: fn(T) -> Option<V>,
355}
356
357impl<I, T, V> MultiAttrIterable<I, T, V>
358where
359    I: Iterator<Item = Result<T, ErrorContext>>,
360{
361    pub fn new(inner: I, f: fn(T) -> Option<V>) -> Self {
362        Self { inner, f }
363    }
364}
365
366impl<I, T, V> Iterator for MultiAttrIterable<I, T, V>
367where
368    I: Iterator<Item = Result<T, ErrorContext>>,
369{
370    type Item = V;
371    fn next(&mut self) -> Option<Self::Item> {
372        match self.inner.next() {
373            Some(Ok(val)) => (self.f)(val),
374            _ => None,
375        }
376    }
377}
378
379#[derive(Clone)]
380pub struct ArrayIterable<I, T>
381where
382    I: Iterator<Item = Result<T, ErrorContext>>,
383{
384    pub(crate) inner: I,
385}
386
387impl<I, T> ArrayIterable<I, T>
388where
389    I: Iterator<Item = Result<T, ErrorContext>>,
390{
391    pub fn new(inner: I) -> Self {
392        Self { inner }
393    }
394}
395
396impl<I, T> Iterator for ArrayIterable<I, T>
397where
398    I: Iterator<Item = Result<T, ErrorContext>>,
399{
400    type Item = T;
401    fn next(&mut self) -> Option<Self::Item> {
402        match self.inner.next() {
403            Some(Ok(val)) => Some(val),
404            _ => None,
405        }
406    }
407}
408
409#[derive(Debug)]
410pub enum RequestBuf<'a> {
411    Ref(&'a mut Vec<u8>),
412    Own(Vec<u8>),
413}
414
415impl RequestBuf<'_> {
416    pub fn buf(&self) -> &Vec<u8> {
417        match self {
418            RequestBuf::Ref(buf) => buf,
419            RequestBuf::Own(buf) => buf,
420        }
421    }
422
423    pub fn buf_mut(&mut self) -> &mut Vec<u8> {
424        match self {
425            RequestBuf::Ref(buf) => buf,
426            RequestBuf::Own(buf) => buf,
427        }
428    }
429}
430
431impl Rec for RequestBuf<'_> {
432    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
433        self.buf_mut()
434    }
435}