netlink-packet 0.1.1

netlink packet types
Documentation
use std::mem::size_of;

use byteorder::{ByteOrder, NativeEndian};
use failure::ResultExt;

use crate::constants::*;
use crate::{DecodeError, DefaultNla, Nla, NlaBuffer, Parseable};

#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct LinkInetDevConf {
    pub forwarding: i32,
    pub mc_forwarding: i32,
    pub proxy_arp: i32,
    pub accept_redirects: i32,
    pub secure_redirects: i32,
    pub send_redirects: i32,
    pub shared_media: i32,
    pub rp_filter: i32,
    pub accept_source_route: i32,
    pub bootp_relay: i32,
    pub log_martians: i32,
    pub tag: i32,
    pub arpfilter: i32,
    pub medium_id: i32,
    pub noxfrm: i32,
    pub nopolicy: i32,
    pub force_igmp_version: i32,
    pub arp_announce: i32,
    pub arp_ignore: i32,
    pub promote_secondaries: i32,
    pub arp_accept: i32,
    pub arp_notify: i32,
    pub accept_local: i32,
    pub src_vmark: i32,
    pub proxy_arp_pvlan: i32,
    pub route_localnet: i32,
    pub igmpv2_unsolicited_report_interval: i32,
    pub igmpv3_unsolicited_report_interval: i32,
    pub ignore_routes_with_linkdown: i32,
    pub drop_unicast_in_l2_multicast: i32,
    pub drop_gratuitous_arp: i32,
}

const LINK_INET_DEV_CONF_LEN: usize = 31 * 4;

impl LinkInetDevConf {
    fn from_bytes(buf: &[u8]) -> Result<Self, DecodeError> {
        if buf.len() < LINK_INET_DEV_CONF_LEN {
            return Err(DecodeError::from(format!(
                "LinkInetDevConf is {} bytes, buffer is only {} bytes: {:#x?}",
                LINK_INET_DEV_CONF_LEN,
                buf.len(),
                buf
            )));
        }
        Ok(LinkInetDevConf {
            forwarding: NativeEndian::read_i32(&buf[0..4]),
            mc_forwarding: NativeEndian::read_i32(&buf[4..8]),
            proxy_arp: NativeEndian::read_i32(&buf[8..12]),
            accept_redirects: NativeEndian::read_i32(&buf[12..16]),
            secure_redirects: NativeEndian::read_i32(&buf[16..20]),
            send_redirects: NativeEndian::read_i32(&buf[20..24]),
            shared_media: NativeEndian::read_i32(&buf[24..28]),
            rp_filter: NativeEndian::read_i32(&buf[28..32]),
            accept_source_route: NativeEndian::read_i32(&buf[32..36]),
            bootp_relay: NativeEndian::read_i32(&buf[36..40]),
            log_martians: NativeEndian::read_i32(&buf[40..44]),
            tag: NativeEndian::read_i32(&buf[44..48]),
            arpfilter: NativeEndian::read_i32(&buf[48..52]),
            medium_id: NativeEndian::read_i32(&buf[52..56]),
            noxfrm: NativeEndian::read_i32(&buf[56..60]),
            nopolicy: NativeEndian::read_i32(&buf[60..64]),
            force_igmp_version: NativeEndian::read_i32(&buf[64..68]),
            arp_announce: NativeEndian::read_i32(&buf[68..72]),
            arp_ignore: NativeEndian::read_i32(&buf[72..76]),
            promote_secondaries: NativeEndian::read_i32(&buf[76..80]),
            arp_accept: NativeEndian::read_i32(&buf[80..84]),
            arp_notify: NativeEndian::read_i32(&buf[84..88]),
            accept_local: NativeEndian::read_i32(&buf[88..92]),
            src_vmark: NativeEndian::read_i32(&buf[92..96]),
            proxy_arp_pvlan: NativeEndian::read_i32(&buf[96..100]),
            route_localnet: NativeEndian::read_i32(&buf[100..104]),
            igmpv2_unsolicited_report_interval: NativeEndian::read_i32(&buf[104..108]),
            igmpv3_unsolicited_report_interval: NativeEndian::read_i32(&buf[108..112]),
            ignore_routes_with_linkdown: NativeEndian::read_i32(&buf[112..116]),
            drop_unicast_in_l2_multicast: NativeEndian::read_i32(&buf[116..120]),
            drop_gratuitous_arp: NativeEndian::read_i32(&buf[120..124]),
        })
    }
    fn to_bytes(&self, buf: &mut [u8]) -> Result<(), DecodeError> {
        if buf.len() < LINK_INET_DEV_CONF_LEN {
            return Err(DecodeError::from(format!(
                "buffer is only {} long, but LinkInetDevConf is {} bytes",
                buf.len(),
                LINK_INET_DEV_CONF_LEN
            )));
        }
        NativeEndian::write_i32(&mut buf[0..4], self.forwarding);
        NativeEndian::write_i32(&mut buf[4..8], self.mc_forwarding);
        NativeEndian::write_i32(&mut buf[8..12], self.proxy_arp);
        NativeEndian::write_i32(&mut buf[12..16], self.accept_redirects);
        NativeEndian::write_i32(&mut buf[16..20], self.secure_redirects);
        NativeEndian::write_i32(&mut buf[20..24], self.send_redirects);
        NativeEndian::write_i32(&mut buf[24..28], self.shared_media);
        NativeEndian::write_i32(&mut buf[28..32], self.rp_filter);
        NativeEndian::write_i32(&mut buf[32..36], self.accept_source_route);
        NativeEndian::write_i32(&mut buf[36..40], self.bootp_relay);
        NativeEndian::write_i32(&mut buf[40..44], self.log_martians);
        NativeEndian::write_i32(&mut buf[44..48], self.tag);
        NativeEndian::write_i32(&mut buf[48..52], self.arpfilter);
        NativeEndian::write_i32(&mut buf[52..56], self.medium_id);
        NativeEndian::write_i32(&mut buf[56..60], self.noxfrm);
        NativeEndian::write_i32(&mut buf[60..64], self.nopolicy);
        NativeEndian::write_i32(&mut buf[64..68], self.force_igmp_version);
        NativeEndian::write_i32(&mut buf[68..72], self.arp_announce);
        NativeEndian::write_i32(&mut buf[72..76], self.arp_ignore);
        NativeEndian::write_i32(&mut buf[76..80], self.promote_secondaries);
        NativeEndian::write_i32(&mut buf[80..84], self.arp_accept);
        NativeEndian::write_i32(&mut buf[84..88], self.arp_notify);
        NativeEndian::write_i32(&mut buf[88..92], self.accept_local);
        NativeEndian::write_i32(&mut buf[92..96], self.src_vmark);
        NativeEndian::write_i32(&mut buf[96..100], self.proxy_arp_pvlan);
        NativeEndian::write_i32(&mut buf[100..104], self.route_localnet);
        NativeEndian::write_i32(&mut buf[104..108], self.igmpv2_unsolicited_report_interval);
        NativeEndian::write_i32(&mut buf[108..112], self.igmpv3_unsolicited_report_interval);
        NativeEndian::write_i32(&mut buf[112..116], self.ignore_routes_with_linkdown);
        NativeEndian::write_i32(&mut buf[116..120], self.drop_unicast_in_l2_multicast);
        NativeEndian::write_i32(&mut buf[120..124], self.drop_gratuitous_arp);
        Ok(())
    }
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub enum LinkAfInetNla {
    DevConf(LinkInetDevConf),
    Unspec(Vec<u8>),
    Other(DefaultNla),
}

impl Nla for LinkAfInetNla {
    #[rustfmt::skip]
    fn value_len(&self) -> usize {
        use self::LinkAfInetNla::*;
        match *self {
            Unspec(ref bytes) => bytes.len(),
            DevConf(_) => size_of::<LinkInetDevConf>(),
            Other(ref nla) => nla.value_len(),
        }
    }

    #[rustfmt::skip]
    fn emit_value(&self, buffer: &mut [u8]) {
        use self::LinkAfInetNla::*;
        match *self {
            Unspec(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),
            DevConf(ref dev_conf) => dev_conf.to_bytes(buffer).expect("check the buffer length before calling emit_value()!"),
            Other(ref nla)  => nla.emit_value(buffer),
        }
    }

    fn kind(&self) -> u16 {
        use self::LinkAfInetNla::*;
        match *self {
            Unspec(_) => IFLA_INET_UNSPEC,
            DevConf(_) => IFLA_INET_CONF,
            Other(ref nla) => nla.kind(),
        }
    }
}

impl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<LinkAfInetNla> for NlaBuffer<&'buffer T> {
    fn parse(&self) -> Result<LinkAfInetNla, DecodeError> {
        use self::LinkAfInetNla::*;
        let payload = self.value();
        Ok(match self.kind() {
            IFLA_INET_UNSPEC => Unspec(payload.to_vec()),
            IFLA_INET_CONF => DevConf(
                LinkInetDevConf::from_bytes(payload).context("invalid IFLA_INET_CONF value")?,
            ),
            kind => Other(
                <Self as Parseable<DefaultNla>>::parse(self)
                    .context(format!("unknown NLA type {}", kind))?,
            ),
        })
    }
}