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 struct MapFormatArray<I, T, M, D>(pub T, pub M)
133where
134    T: Clone + Iterator<Item = Result<I, ErrorContext>>,
135    M: Clone + FnMut(I) -> D,
136    D: fmt::Debug;
137
138impl<I, T, M, D> fmt::Debug for MapFormatArray<I, T, M, D>
139where
140    T: Clone + Iterator<Item = Result<I, ErrorContext>>,
141    M: Clone + FnMut(I) -> D,
142    D: fmt::Debug,
143{
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        let mut f = f.debug_list();
146        for item in self.0.clone() {
147            f.entry(&FlattenErrorContext(item.map(self.1.clone())));
148        }
149        f.finish()
150    }
151}
152
153pub const NLA_F_NESTED: u16 = 1 << 15;
154pub const NLA_F_NET_BYTEORDER: u16 = 1 << 14;
155
156pub const fn nla_type(r#type: u16) -> u16 {
157    r#type & (!(NLA_F_NESTED | NLA_F_NET_BYTEORDER))
158}
159
160pub const NLA_ALIGNTO: usize = 4;
161
162pub const fn nla_align_up(len: usize) -> usize {
163    ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
164}
165
166pub fn align(buf: &mut Vec<u8>) {
167    let len = buf.len();
168    buf.extend(std::iter::repeat_n(0u8, nla_align_up(len) - len));
169}
170
171/// Returns header offset
172pub fn push_nested_header(buf: &mut Vec<u8>, r#type: u16) -> usize {
173    push_header_type(buf, r#type, 0, true)
174}
175
176/// Returns header offset
177pub fn push_header(buf: &mut Vec<u8>, r#type: u16, len: u16) -> usize {
178    push_header_type(buf, r#type, len, false)
179}
180
181/// Returns header offset
182/// The kernel doesn't really check byteorder bit nor set it correctly
183fn push_header_type(buf: &mut Vec<u8>, mut r#type: u16, len: u16, is_nested: bool) -> usize {
184    align(buf);
185
186    let header_offset = buf.len();
187
188    if is_nested {
189        r#type |= NLA_F_NESTED;
190    }
191
192    // TODO: alignment for 8 byte types?
193    buf.extend((len + 4).to_ne_bytes());
194    buf.extend(r#type.to_ne_bytes());
195
196    align(buf);
197
198    header_offset
199}
200
201pub fn finalize_nested_header(buf: &mut Vec<u8>, offset: usize) {
202    align(buf);
203
204    let len = (buf.len() - offset) as u16;
205    buf[offset..(offset + 2)].copy_from_slice(&len.to_ne_bytes());
206}
207
208#[derive(Debug, Clone, Copy)]
209pub struct Header {
210    pub r#type: u16,
211    pub is_nested: bool,
212}
213
214pub fn chop_header<'a>(buf: &'a [u8], pos: &mut usize) -> Option<(Header, &'a [u8])> {
215    let buf = &buf[*pos..];
216
217    if buf.len() < 4 {
218        return None;
219    }
220
221    let len = parse_u16(&buf[0..2]).unwrap();
222    let r#type = parse_u16(&buf[2..4]).unwrap();
223
224    let next_len = nla_align_up(len as usize);
225
226    if len < 4 || buf.len() < len as usize {
227        return None;
228    }
229
230    let next = &buf[4..len as usize];
231    *pos += next_len.min(buf.len());
232
233    Some((
234        Header {
235            r#type: nla_type(r#type),
236            is_nested: r#type & NLA_F_NESTED != 0,
237        },
238        next,
239    ))
240}
241
242pub trait Rec {
243    fn as_rec_mut(&mut self) -> &mut Vec<u8>;
244}
245
246impl Rec for &mut Vec<u8> {
247    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
248        self
249    }
250}
251
252#[derive(Debug, Clone, PartialEq, Eq)]
253pub enum ErrorReason {
254    /// Only used in `.get_<attr>()` methods
255    AttrMissing,
256    /// Value of the attribute can't be parsed
257    ParsingError,
258    /// Found attribute of type not mentioned in the specification
259    UnknownAttr,
260}
261
262#[derive(Clone, PartialEq, Eq)]
263pub struct ErrorContext {
264    pub attrs: &'static str,
265    pub attr: Option<&'static str>,
266    pub offset: usize,
267    pub reason: ErrorReason,
268}
269
270impl std::error::Error for ErrorContext {}
271
272impl From<ErrorContext> for std::io::Error {
273    fn from(value: ErrorContext) -> Self {
274        Self::other(value)
275    }
276}
277
278impl fmt::Debug for ErrorContext {
279    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280        f.debug_struct("ErrorContext")
281            .field("message", &DisplayAsDebug(&self))
282            .field("reason", &self.reason)
283            .field("attrs", &self.attrs)
284            .field("attr", &self.attr)
285            .field("offset", &self.offset)
286            .finish()
287    }
288}
289
290impl fmt::Display for ErrorContext {
291    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292        let attrs = self.attrs;
293        if matches!(self.reason, ErrorReason::AttrMissing) {
294            let attr = self.attr.unwrap();
295            write!(f, "Missing attribute {attr:?} in {attrs:?}")?;
296            return Ok(());
297        } else {
298            write!(f, "Error parsing ")?;
299            if let Some(attr) = self.attr {
300                write!(f, "attribute {attr:?} of {attrs:?}")?;
301            } else {
302                write!(f, "header of {attrs:?}")?;
303                if matches!(self.reason, ErrorReason::UnknownAttr) {
304                    write!(f, " (unknown attribute)")?;
305                }
306            }
307        }
308        write!(f, " at offset {}", self.offset)?;
309        Ok(())
310    }
311}
312
313impl ErrorContext {
314    #[cold]
315    pub(crate) fn new(
316        attrs: &'static str,
317        attr: Option<&'static str>,
318        orig_loc: usize,
319        loc: usize,
320    ) -> ErrorContext {
321        let ctx = ErrorContext {
322            attrs,
323            attr,
324            offset: Self::calc_offset(orig_loc, loc),
325            reason: if attr.is_some() {
326                ErrorReason::ParsingError
327            } else {
328                ErrorReason::UnknownAttr
329            },
330        };
331
332        if cfg!(test) {
333            panic!("{ctx}")
334        } else {
335            ctx
336        }
337    }
338
339    #[cold]
340    pub(crate) fn new_missing(
341        attrs: &'static str,
342        attr: &'static str,
343        orig_loc: usize,
344        loc: usize,
345    ) -> ErrorContext {
346        let ctx = ErrorContext {
347            attrs,
348            attr: Some(attr),
349            offset: Self::calc_offset(orig_loc, loc),
350            reason: ErrorReason::AttrMissing,
351        };
352
353        if cfg!(test) {
354            panic!("{ctx}")
355        } else {
356            ctx
357        }
358    }
359
360    pub(crate) fn calc_offset(orig_loc: usize, loc: usize) -> usize {
361        if orig_loc <= loc && loc - orig_loc <= u16::MAX as usize {
362            loc - orig_loc
363        } else {
364            0
365        }
366    }
367}
368
369#[derive(Clone)]
370pub struct MultiAttrIterable<I, T, V>
371where
372    I: Iterator<Item = Result<T, ErrorContext>>,
373{
374    pub(crate) inner: I,
375    pub(crate) f: fn(T) -> Option<V>,
376}
377
378impl<I, T, V> MultiAttrIterable<I, T, V>
379where
380    I: Iterator<Item = Result<T, ErrorContext>>,
381{
382    pub fn new(inner: I, f: fn(T) -> Option<V>) -> Self {
383        Self { inner, f }
384    }
385}
386
387impl<I, T, V> Iterator for MultiAttrIterable<I, T, V>
388where
389    I: Iterator<Item = Result<T, ErrorContext>>,
390{
391    type Item = V;
392    fn next(&mut self) -> Option<Self::Item> {
393        match self.inner.next() {
394            Some(Ok(val)) => (self.f)(val),
395            _ => None,
396        }
397    }
398}
399
400#[derive(Clone)]
401pub struct ArrayIterable<I, T>
402where
403    I: Iterator<Item = Result<T, ErrorContext>>,
404{
405    pub(crate) inner: I,
406}
407
408impl<I, T> ArrayIterable<I, T>
409where
410    I: Iterator<Item = Result<T, ErrorContext>>,
411{
412    pub fn new(inner: I) -> Self {
413        Self { inner }
414    }
415}
416
417impl<I, T> Iterator for ArrayIterable<I, T>
418where
419    I: Iterator<Item = Result<T, ErrorContext>>,
420{
421    type Item = T;
422    fn next(&mut self) -> Option<Self::Item> {
423        match self.inner.next() {
424            Some(Ok(val)) => Some(val),
425            _ => None,
426        }
427    }
428}
429
430#[derive(Debug)]
431pub enum RequestBuf<'a> {
432    Ref(&'a mut Vec<u8>),
433    Own(Vec<u8>),
434}
435
436impl RequestBuf<'_> {
437    pub fn buf(&self) -> &Vec<u8> {
438        match self {
439            RequestBuf::Ref(buf) => buf,
440            RequestBuf::Own(buf) => buf,
441        }
442    }
443
444    pub fn buf_mut(&mut self) -> &mut Vec<u8> {
445        match self {
446            RequestBuf::Ref(buf) => buf,
447            RequestBuf::Own(buf) => buf,
448        }
449    }
450}
451
452impl Rec for RequestBuf<'_> {
453    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
454        self.buf_mut()
455    }
456}