1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright (C) 2018 - Will Glozer. All rights reserved.

use std::convert::TryFrom;
use std::iter;
use crate::err::Invalid;
use crate::ffi::*;
use crate::sys::{Cursor, Bytes, Message};
use super::{IFA, IFLA, NDA, RTA};

#[derive(Debug)]
pub enum Any<'a> {
    IFAddr(Message<'a, ifaddrmsg>),
    IFInfo(Message<'a, ifinfomsg>),
    Peer(Message<'a, ndmsg>),
    Route(Message<'a, rtmsg>),
    Unsupported(u16, Cursor<'a>),
}

impl<'a> Message<'a, ifaddrmsg> {
    pub fn attrs(&self) -> impl Iterator<Item = Result<IFA<'a>, Invalid>> {
        let mut tail = self.tail();
        iter::from_fn(move || tail.next().map(IFA::try_from))
    }
}

impl<'a> Message<'a, ifinfomsg> {
    pub fn attrs(&self) -> impl Iterator<Item = Result<IFLA<'a>, Invalid>> {
        let mut tail = self.tail();
        iter::from_fn(move || tail.next().map(IFLA::try_from))
    }
}

impl<'a> Message<'a, ndmsg> {
    pub fn attrs(&self) -> impl Iterator<Item = Result<NDA<'a>, Invalid>> {
        let mut tail = self.tail();
        iter::from_fn(move || tail.next().map(NDA::try_from))
    }
}

impl<'a> Message<'a, rtmsg> {
    pub fn attrs(&self) -> impl Iterator<Item = Result<RTA<'a>, Invalid>> {
        let mut tail = self.tail();
        iter::from_fn(move || tail.next().map(RTA::try_from))
    }
}

impl<'a> Message<'a, inet_diag_msg> {
    pub fn info<T: Bytes>(&self) -> Option<T> {
        let mut tail = self.tail();
        while let Some((attr, mut tail)) = tail.next::<rtattr>() {
            if attr.rta_type == INET_DIAG_INFO {
                return Some(tail.next()?.0);
            }
        }
        None
    }
}

impl<'a> Message<'a, ()> {
    pub fn any(&self) -> Any<'a> {
        match self.nlmsg_type() {
            RTM_NEWADDR  | RTM_DELADDR  => Any::IFAddr(self.msg()),
            RTM_NEWLINK  | RTM_DELLINK  => Any::IFInfo(self.msg()),
            RTM_NEWNEIGH | RTM_DELNEIGH => Any::Peer(self.msg()),
            RTM_NEWROUTE | RTM_DELROUTE => Any::Route(self.msg()),
            kind                        => Any::Unsupported(kind, self.tail()),
        }
    }

    fn msg<T: Bytes + Default>(&self) -> Message<'a, T> {
        let (head, _, mut tail) = self.parts();
        let (data, tail) = tail.next().unwrap_or_default();
        Message::with(head.clone(), data, tail)
    }
}