netlink_packet_generic/ctrl/
mod.rs

1// SPDX-License-Identifier: MIT
2
3//! Generic netlink controller implementation
4//!
5//! This module provides the definition of the controller packet.
6//! It also serves as an example for creating a generic family.
7
8use self::nlas::*;
9use crate::{constants::*, traits::*, GenlHeader};
10use anyhow::Context;
11use netlink_packet_utils::{nla::NlasIterator, traits::*, DecodeError};
12use std::convert::{TryFrom, TryInto};
13
14/// Netlink attributes for this family
15pub mod nlas;
16
17/// Command code definition of Netlink controller (nlctrl) family
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub enum GenlCtrlCmd {
20    /// Notify from event
21    NewFamily,
22    /// Notify from event
23    DelFamily,
24    /// Request to get family info
25    GetFamily,
26    /// Currently unused
27    NewOps,
28    /// Currently unused
29    DelOps,
30    /// Currently unused
31    GetOps,
32    /// Notify from event
33    NewMcastGrp,
34    /// Notify from event
35    DelMcastGrp,
36    /// Currently unused
37    GetMcastGrp,
38    /// Request to get family policy
39    GetPolicy,
40}
41
42impl From<GenlCtrlCmd> for u8 {
43    fn from(cmd: GenlCtrlCmd) -> u8 {
44        use GenlCtrlCmd::*;
45        match cmd {
46            NewFamily => CTRL_CMD_NEWFAMILY,
47            DelFamily => CTRL_CMD_DELFAMILY,
48            GetFamily => CTRL_CMD_GETFAMILY,
49            NewOps => CTRL_CMD_NEWOPS,
50            DelOps => CTRL_CMD_DELOPS,
51            GetOps => CTRL_CMD_GETOPS,
52            NewMcastGrp => CTRL_CMD_NEWMCAST_GRP,
53            DelMcastGrp => CTRL_CMD_DELMCAST_GRP,
54            GetMcastGrp => CTRL_CMD_GETMCAST_GRP,
55            GetPolicy => CTRL_CMD_GETPOLICY,
56        }
57    }
58}
59
60impl TryFrom<u8> for GenlCtrlCmd {
61    type Error = DecodeError;
62
63    fn try_from(value: u8) -> Result<Self, Self::Error> {
64        use GenlCtrlCmd::*;
65        Ok(match value {
66            CTRL_CMD_NEWFAMILY => NewFamily,
67            CTRL_CMD_DELFAMILY => DelFamily,
68            CTRL_CMD_GETFAMILY => GetFamily,
69            CTRL_CMD_NEWOPS => NewOps,
70            CTRL_CMD_DELOPS => DelOps,
71            CTRL_CMD_GETOPS => GetOps,
72            CTRL_CMD_NEWMCAST_GRP => NewMcastGrp,
73            CTRL_CMD_DELMCAST_GRP => DelMcastGrp,
74            CTRL_CMD_GETMCAST_GRP => GetMcastGrp,
75            CTRL_CMD_GETPOLICY => GetPolicy,
76            cmd => {
77                return Err(DecodeError::from(format!(
78                    "Unknown control command: {cmd}"
79                )))
80            }
81        })
82    }
83}
84
85/// Payload of generic netlink controller
86#[derive(Clone, Debug, PartialEq, Eq)]
87pub struct GenlCtrl {
88    /// Command code of this message
89    pub cmd: GenlCtrlCmd,
90    /// Netlink attributes in this message
91    pub nlas: Vec<GenlCtrlAttrs>,
92}
93
94impl GenlFamily for GenlCtrl {
95    fn family_name() -> &'static str {
96        "nlctrl"
97    }
98
99    fn family_id(&self) -> u16 {
100        GENL_ID_CTRL
101    }
102
103    fn command(&self) -> u8 {
104        self.cmd.into()
105    }
106
107    fn version(&self) -> u8 {
108        2
109    }
110}
111
112impl Emitable for GenlCtrl {
113    fn emit(&self, buffer: &mut [u8]) {
114        self.nlas.as_slice().emit(buffer)
115    }
116
117    fn buffer_len(&self) -> usize {
118        self.nlas.as_slice().buffer_len()
119    }
120}
121
122impl ParseableParametrized<[u8], GenlHeader> for GenlCtrl {
123    fn parse_with_param(
124        buf: &[u8],
125        header: GenlHeader,
126    ) -> Result<Self, DecodeError> {
127        Ok(Self {
128            cmd: header.cmd.try_into()?,
129            nlas: parse_ctrlnlas(buf)?,
130        })
131    }
132}
133
134fn parse_ctrlnlas(buf: &[u8]) -> Result<Vec<GenlCtrlAttrs>, DecodeError> {
135    let nlas = NlasIterator::new(buf)
136        .map(|nla| nla.and_then(|nla| GenlCtrlAttrs::parse(&nla)))
137        .collect::<Result<Vec<_>, _>>()
138        .context("failed to parse control message attributes")?;
139
140    Ok(nlas)
141}