Skip to main content

netlink_bindings/
utils.rs

1use std::fmt;
2
3pub use crate::primitives::*;
4pub use crate::traits::Pusher;
5pub use std::{ffi::CStr, fmt::Debug, iter::Iterator};
6
7pub fn dump_hex(buf: &[u8]) {
8    let mut len = 0;
9    for chunk in buf.chunks(16) {
10        print!("{len:04x?}: ");
11        print!("{chunk:02x?} ");
12        for b in chunk {
13            if b.is_ascii() && !b.is_ascii_control() {
14                print!("{}", char::from_u32(*b as u32).unwrap());
15            } else {
16                print!(".");
17            }
18        }
19        println!();
20        len += chunk.len();
21    }
22}
23
24pub fn dump_assert_eq(left: &[u8], right: &[u8]) {
25    if left.len() != right.len() {
26        dump_hex(left);
27        dump_hex(right);
28        panic!("Length mismatched");
29    }
30    if let Some(pos) = left.iter().zip(right.iter()).position(|(l, r)| *l != *r) {
31        println!();
32        println!("Left:");
33        dump_hex(left);
34        println!();
35        println!("Right:");
36        dump_hex(right);
37        panic!("Differ at byte {pos} (0x{pos:x?})");
38    }
39}
40
41pub struct FormatBinStr<T: AsRef<[u8]>>(pub T);
42impl<T: AsRef<[u8]>> Debug for FormatBinStr<T> {
43    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
44        // core::bstr is currently unstable
45        let bstr = self.0.as_ref();
46        if let Ok(cstr) = CStr::from_bytes_with_nul(bstr) {
47            write!(fmt, "{cstr:?}")?;
48        } else {
49            for c in bstr.chunks(127) {
50                let mut buf = [0u8; 128];
51                buf[..c.len()].clone_from_slice(c);
52                write!(fmt, "{:?}", CStr::from_bytes_until_nul(&buf).unwrap())?;
53            }
54        };
55        Ok(())
56    }
57}
58
59pub struct FormatIter<I: Iterator<Item = T> + Clone, T: Debug>(pub I);
60
61impl<I: Iterator<Item = T> + Clone, T: Debug> Debug for FormatIter<I, T> {
62    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
63        let mut f = fmt.debug_list();
64        for item in self.0.clone() {
65            f.entry(&item);
66        }
67        f.finish()
68    }
69}
70
71pub struct FormatHex<T: AsRef<[u8]>>(pub T);
72
73impl<T: AsRef<[u8]>> Debug for FormatHex<T> {
74    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
75        write!(fmt, "\"")?;
76        for i in self.0.as_ref() {
77            write!(fmt, "{i:02x}")?
78        }
79        write!(fmt, "\"")?;
80        Ok(())
81    }
82}
83
84pub struct FormatMac<T: AsRef<[u8]>>(pub T);
85
86impl<T: AsRef<[u8]>> Debug for FormatMac<T> {
87    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
88        let mut first = true;
89        for i in self.0.as_ref() {
90            if !first {
91                write!(fmt, ":")?;
92            }
93            first = false;
94            write!(fmt, "{i:02x}")?;
95        }
96        Ok(())
97    }
98}
99
100pub struct FormatEnum<T: Debug>(pub u64, pub fn(u64) -> Option<T>);
101
102impl<T: Debug> Debug for FormatEnum<T> {
103    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
104        write!(fmt, "{} ", self.0)?;
105
106        if let Some(var) = (self.1)(self.0) {
107            write!(fmt, "[{var:?}]")?;
108        } else {
109            write!(fmt, "(unknown variant)")?;
110        }
111
112        Ok(())
113    }
114}
115
116pub struct FormatFlags<T: Debug>(pub u64, pub fn(u64) -> Option<T>);
117
118impl<T: Debug> Debug for FormatFlags<T> {
119    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
120        write!(fmt, "{} ", self.0)?;
121
122        if self.0 == 0 {
123            write!(fmt, "(empty)")?;
124            return Ok(());
125        }
126
127        let mut seen_variant = false;
128        for i in 0..u64::BITS {
129            let bit = self.0 & (1 << i);
130            if bit == 0 {
131                continue;
132            }
133
134            if !seen_variant {
135                seen_variant = true;
136                write!(fmt, "[")?;
137            } else {
138                write!(fmt, ",")?;
139            }
140
141            if let Some(var) = (self.1)(bit) {
142                write!(fmt, "{var:?}")?;
143            } else {
144                write!(fmt, "(unknown bit {i})")?;
145            }
146        }
147
148        if seen_variant {
149            write!(fmt, "]")?;
150        }
151
152        Ok(())
153    }
154}
155
156pub struct DisplayAsDebug<T>(T);
157
158impl<T: fmt::Display> fmt::Debug for DisplayAsDebug<T> {
159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160        write!(f, "{}", self.0)
161    }
162}
163
164pub struct FlattenErrorContext<T: fmt::Debug>(pub Result<T, ErrorContext>);
165
166impl<T: Debug> fmt::Debug for FlattenErrorContext<T> {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        match &self.0 {
169            Ok(ok) => ok.fmt(f),
170            Err(err) => {
171                f.write_str("Err(")?;
172                err.fmt(f)?;
173                f.write_str(")")
174            }
175        }
176    }
177}
178
179pub struct MapFormatArray<I, T, M, D>(pub T, pub M)
180where
181    T: Clone + Iterator<Item = Result<I, ErrorContext>>,
182    M: Clone + FnMut(I) -> D,
183    D: fmt::Debug;
184
185impl<I, T, M, D> fmt::Debug for MapFormatArray<I, T, M, D>
186where
187    T: Clone + Iterator<Item = Result<I, ErrorContext>>,
188    M: Clone + FnMut(I) -> D,
189    D: fmt::Debug,
190{
191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        let mut f = f.debug_list();
193        for item in self.0.clone() {
194            f.entry(&FlattenErrorContext(item.map(self.1.clone())));
195        }
196        f.finish()
197    }
198}
199
200pub const NLA_F_NESTED: u16 = 1 << 15;
201pub const NLA_F_NET_BYTEORDER: u16 = 1 << 14;
202
203pub const fn nla_type(r#type: u16) -> u16 {
204    r#type & (!(NLA_F_NESTED | NLA_F_NET_BYTEORDER))
205}
206
207pub const NLA_ALIGNTO: usize = 4;
208
209pub const fn align_up(len: usize, alignment: usize) -> usize {
210    ((len) + alignment - 1) & !(alignment - 1)
211}
212
213pub const fn nla_align_up(len: usize) -> usize {
214    ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
215}
216
217pub fn align(buf: &mut Vec<u8>) {
218    let len = buf.len();
219    buf.extend(std::iter::repeat_n(0u8, nla_align_up(len) - len));
220}
221
222/// Returns header offset
223pub fn push_nested_header(buf: &mut Vec<u8>, r#type: u16) -> usize {
224    push_header_type(buf, r#type, 0, true)
225}
226
227/// Returns header offset
228pub fn push_header(buf: &mut Vec<u8>, r#type: u16, len: u16) -> usize {
229    push_header_type(buf, r#type, len, false)
230}
231
232/// Returns header offset
233pub fn write_header(buf: &mut Vec<u8>, r#type: u16) -> usize {
234    push_header_type(buf, r#type, 0, false)
235}
236
237/// Returns header offset
238/// The kernel doesn't really check byteorder bit nor set it correctly
239fn push_header_type(buf: &mut Vec<u8>, mut r#type: u16, len: u16, is_nested: bool) -> usize {
240    align(buf);
241
242    let header_offset = buf.len();
243
244    if is_nested {
245        r#type |= NLA_F_NESTED;
246    }
247
248    // TODO: alignment for 8 byte types?
249    buf.extend((len + 4).to_ne_bytes());
250    buf.extend(r#type.to_ne_bytes());
251
252    header_offset
253}
254
255pub fn push_pad(buf: &mut Vec<u8>, pad_type: u16, alignment: usize) {
256    assert!(alignment.is_power_of_two());
257    if alignment <= 4 {
258        return;
259    }
260
261    align(buf);
262
263    let needed = align_up(buf.len(), alignment) - buf.len();
264
265    if needed == 0 {
266        return;
267    }
268
269    push_header(buf, pad_type, (needed - 4) as u16);
270    buf.extend(std::iter::repeat_n(0, needed - 4));
271}
272
273pub fn finalize_nested_header(buf: &mut Vec<u8>, offset: usize) {
274    align(buf);
275
276    let len = (buf.len() - offset) as u16;
277    buf[offset..(offset + 2)].copy_from_slice(&len.to_ne_bytes());
278}
279
280/// A convenience wrapper on top of [`chop_header()`]
281#[derive(Debug, Clone, Copy, Default)]
282pub struct IterableChunks<'buf> {
283    /// A buffer given to [`Self::new()`]
284    pub buf: &'buf [u8],
285    /// Offset of the next attribute in [`Self::buf`]
286    pub pos: usize,
287}
288
289impl<'buf> IterableChunks<'buf> {
290    pub fn new(buf: &'buf [u8]) -> Self {
291        Self { buf, pos: 0 }
292    }
293    pub fn is_empty(&self) -> bool {
294        self.buf.len() == self.pos
295    }
296}
297
298impl<'buf> Iterator for IterableChunks<'buf> {
299    type Item = (Header, &'buf [u8]);
300    fn next(&mut self) -> Option<Self::Item> {
301        chop_header(self.buf, &mut self.pos)
302    }
303}
304
305#[derive(Debug, Clone, Copy)]
306pub struct Header {
307    pub r#type: u16,
308    pub is_nested: bool,
309}
310
311pub fn chop_header<'a>(buf: &'a [u8], pos: &mut usize) -> Option<(Header, &'a [u8])> {
312    let buf = &buf[*pos..];
313
314    if buf.len() < 4 {
315        return None;
316    }
317
318    let len = parse_u16(&buf[0..2]).unwrap();
319    let r#type = parse_u16(&buf[2..4]).unwrap();
320
321    let next_len = nla_align_up(len as usize);
322
323    if len < 4 || buf.len() < len as usize {
324        return None;
325    }
326
327    let next = &buf[4..len as usize];
328    *pos += next_len.min(buf.len());
329
330    Some((
331        Header {
332            r#type: nla_type(r#type),
333            is_nested: r#type & NLA_F_NESTED != 0,
334        },
335        next,
336    ))
337}
338
339// TODO: drop in v0.4
340#[deprecated = "Use netlink_bindings::traits::Pusher instead"]
341pub use crate::traits::Pusher as Rec;
342
343#[derive(Debug, Clone, PartialEq, Eq)]
344pub enum ErrorReason {
345    /// Only used in `.get_<attr>()` methods
346    AttrMissing,
347    /// Value of the attribute can't be parsed
348    ParsingError,
349    /// Found attribute of type not mentioned in the specification
350    UnknownAttr,
351}
352
353#[derive(Clone, PartialEq, Eq)]
354pub struct ErrorContext {
355    pub attrs: &'static str,
356    pub attr: Option<&'static str>,
357    pub offset: usize,
358    pub reason: ErrorReason,
359}
360
361impl std::error::Error for ErrorContext {}
362
363impl From<ErrorContext> for std::io::Error {
364    fn from(value: ErrorContext) -> Self {
365        Self::other(value)
366    }
367}
368
369impl fmt::Debug for ErrorContext {
370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371        f.debug_struct("ErrorContext")
372            .field("message", &DisplayAsDebug(&self))
373            .field("reason", &self.reason)
374            .field("attrs", &self.attrs)
375            .field("attr", &self.attr)
376            .field("offset", &self.offset)
377            .finish()
378    }
379}
380
381impl fmt::Display for ErrorContext {
382    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383        let attrs = self.attrs;
384        if matches!(self.reason, ErrorReason::AttrMissing) {
385            let attr = self.attr.unwrap();
386            write!(f, "Missing attribute {attr:?} in {attrs:?}")?;
387            return Ok(());
388        } else {
389            write!(f, "Error parsing ")?;
390            if let Some(attr) = self.attr {
391                write!(f, "attribute {attr:?} of {attrs:?}")?;
392            } else {
393                write!(f, "header of {attrs:?}")?;
394                if matches!(self.reason, ErrorReason::UnknownAttr) {
395                    write!(f, " (unknown attribute)")?;
396                }
397            }
398        }
399        write!(f, " at offset {} (0x{:02x})", self.offset, self.offset)?;
400        Ok(())
401    }
402}
403
404impl ErrorContext {
405    #[cold]
406    pub(crate) fn new(
407        attrs: &'static str,
408        attr: Option<&'static str>,
409        orig_loc: usize,
410        loc: usize,
411    ) -> ErrorContext {
412        let ctx = ErrorContext {
413            attrs,
414            attr,
415            offset: Self::calc_offset(orig_loc, loc),
416            reason: if attr.is_some() {
417                ErrorReason::ParsingError
418            } else {
419                ErrorReason::UnknownAttr
420            },
421        };
422
423        if cfg!(test) {
424            panic!("{ctx}")
425        } else {
426            ctx
427        }
428    }
429
430    #[cold]
431    pub(crate) fn new_missing(
432        attrs: &'static str,
433        attr: &'static str,
434        orig_loc: usize,
435        loc: usize,
436    ) -> ErrorContext {
437        let ctx = ErrorContext {
438            attrs,
439            attr: Some(attr),
440            offset: Self::calc_offset(orig_loc, loc),
441            reason: ErrorReason::AttrMissing,
442        };
443
444        if cfg!(test) {
445            panic!("{ctx}")
446        } else {
447            ctx
448        }
449    }
450
451    pub(crate) fn calc_offset(orig_loc: usize, loc: usize) -> usize {
452        if orig_loc <= loc && loc - orig_loc <= u16::MAX as usize {
453            loc - orig_loc
454        } else {
455            0
456        }
457    }
458}
459
460#[derive(Clone, Copy)]
461pub struct MultiAttrIterable<I, T, V>
462where
463    I: Iterator<Item = Result<T, ErrorContext>>,
464{
465    pub(crate) inner: I,
466    pub(crate) f: fn(T) -> Option<V>,
467}
468
469impl<I, T, V> MultiAttrIterable<I, T, V>
470where
471    I: Iterator<Item = Result<T, ErrorContext>>,
472{
473    pub fn new(inner: I, f: fn(T) -> Option<V>) -> Self {
474        Self { inner, f }
475    }
476}
477
478impl<I, T, V> Iterator for MultiAttrIterable<I, T, V>
479where
480    I: Iterator<Item = Result<T, ErrorContext>>,
481{
482    type Item = V;
483    fn next(&mut self) -> Option<Self::Item> {
484        match self.inner.next() {
485            Some(Ok(val)) => (self.f)(val),
486            _ => None,
487        }
488    }
489}
490
491#[derive(Clone, Copy, Default)]
492pub struct ArrayIterable<I, T>
493where
494    I: Iterator<Item = Result<T, ErrorContext>>,
495{
496    pub(crate) inner: I,
497}
498
499impl<I, T> ArrayIterable<I, T>
500where
501    I: Iterator<Item = Result<T, ErrorContext>>,
502{
503    pub fn new(inner: I) -> Self {
504        Self { inner }
505    }
506}
507
508impl<I, T> Iterator for ArrayIterable<I, T>
509where
510    I: Iterator<Item = Result<T, ErrorContext>>,
511{
512    type Item = T;
513    fn next(&mut self) -> Option<Self::Item> {
514        match self.inner.next() {
515            Some(Ok(val)) => Some(val),
516            _ => None,
517        }
518    }
519}
520
521#[derive(Debug)]
522pub enum RequestBuf<'a> {
523    Ref(&'a mut Vec<u8>),
524    Own(Vec<u8>),
525}
526
527impl RequestBuf<'_> {
528    pub fn buf(&self) -> &Vec<u8> {
529        match self {
530            RequestBuf::Ref(buf) => buf,
531            RequestBuf::Own(buf) => buf,
532        }
533    }
534
535    pub fn buf_mut(&mut self) -> &mut Vec<u8> {
536        match self {
537            RequestBuf::Ref(buf) => buf,
538            RequestBuf::Own(buf) => buf,
539        }
540    }
541}
542
543impl Pusher for RequestBuf<'_> {
544    fn as_vec_mut(&mut self) -> &mut Vec<u8> {
545        self.buf_mut()
546    }
547    fn as_vec(&self) -> &Vec<u8> {
548        self.buf()
549    }
550}
551
552pub struct PushWriter<Prev: Pusher> {
553    pub(crate) prev: Option<Prev>,
554    pub(crate) header_offset: Option<usize>,
555}
556
557impl<Prev: Pusher> std::ops::Deref for PushWriter<Prev> {
558    type Target = Vec<u8>;
559    fn deref(&self) -> &Self::Target {
560        self.as_vec()
561    }
562}
563
564impl<Prev: Pusher> std::ops::DerefMut for PushWriter<Prev> {
565    fn deref_mut(&mut self) -> &mut Self::Target {
566        self.as_vec_mut()
567    }
568}
569
570impl<Prev: Pusher> std::io::Write for PushWriter<Prev> {
571    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
572        self.as_vec_mut().write(buf)
573    }
574    fn flush(&mut self) -> std::io::Result<()> {
575        self.as_vec_mut().flush()
576    }
577}
578
579impl<Prev: Pusher> Pusher for PushWriter<Prev> {
580    fn as_vec_mut(&mut self) -> &mut Vec<u8> {
581        self.prev.as_mut().unwrap().as_vec_mut()
582    }
583    fn as_vec(&self) -> &Vec<u8> {
584        self.prev.as_ref().unwrap().as_vec()
585    }
586}
587
588impl<Prev: Pusher> PushWriter<Prev> {
589    pub fn new(prev: Prev) -> Self {
590        Self {
591            prev: Some(prev),
592            header_offset: None,
593        }
594    }
595    pub fn end_nested(mut self) -> Prev {
596        let mut prev = self.prev.take().unwrap();
597        if let Some(header_offset) = &self.header_offset {
598            finalize_nested_header(prev.as_vec_mut(), *header_offset);
599        }
600        prev
601    }
602}
603
604impl<Prev: Pusher> Drop for PushWriter<Prev> {
605    fn drop(&mut self) {
606        if let Some(prev) = &mut self.prev {
607            if let Some(header_offset) = &self.header_offset {
608                finalize_nested_header(prev.as_vec_mut(), *header_offset);
609            }
610        }
611    }
612}
613
614pub fn get_bits(buf: &[u8], byte_off: usize, bit_off: usize, bits: usize) -> u32 {
615    assert!(bit_off < 8);
616    assert!(bits <= 32);
617
618    let max_bytes = (bit_off + bits).div_ceil(8);
619    let first = byte_off;
620    let last = byte_off + max_bytes;
621
622    let mut reg_buf = [0u8; 8];
623    reg_buf[..max_bytes].copy_from_slice(&buf[first..last]);
624    let reg = u64::from_le_bytes(reg_buf) << (64 - bit_off - bits) >> (64 - bits);
625    reg.to_le() as u32
626}
627
628pub fn set_bits(buf: &mut [u8], byte_off: usize, bit_off: usize, bits: usize, val: u32) {
629    assert!(bit_off < 8);
630    assert!(bits <= 32);
631
632    let max_bytes = (bit_off + bits).div_ceil(8);
633    let first = byte_off;
634    let last = byte_off + max_bytes;
635
636    let mask = !(((1 << bits) - 1) << bit_off);
637    let reg = (val as u64) << bit_off;
638    let mut reg_buf = [0u8; 8];
639    reg_buf[..max_bytes].copy_from_slice(&buf[first..last]);
640    let reg = (u64::from_le_bytes(reg_buf) & mask) | reg;
641    let reg_buf = reg.to_le_bytes();
642    buf[first..last].copy_from_slice(&reg_buf[..max_bytes])
643}
644
645#[cfg(test)]
646mod tests {
647    use super::*;
648
649    #[test]
650    fn test_get_bits_basic() {
651        let buf = &[0b1010_0110u8, 0b0000_1100];
652
653        assert_eq!(get_bits(buf, 0, 0, 4), 0b0110);
654        assert_eq!(get_bits(buf, 0, 4, 4), 0b1010);
655        assert_eq!(get_bits(buf, 0, 4, 8), 0b1100_1010);
656    }
657
658    #[test]
659    fn test_set_bits_basic() {
660        let buf = &mut [0u8; 2];
661
662        set_bits(buf, 0, 0, 4, 0b0110);
663        assert_eq!(buf[0], 0b0110);
664
665        set_bits(buf, 0, 4, 4, 0b1111);
666        assert_eq!(buf[0], 0b1111_0110);
667
668        set_bits(buf, 0, 4, 8, 0b1100_1010);
669        assert_eq!(buf, &[0b1010_0110, 0b0000_1100]);
670    }
671}