netlink_packet_generic/ctrl/nlas/
policy.rs

1// SPDX-License-Identifier: MIT
2
3use crate::constants::*;
4use anyhow::Context;
5use byteorder::{ByteOrder, NativeEndian};
6use netlink_packet_utils::nla::{Nla, NlaBuffer, NlasIterator};
7use netlink_packet_utils::parsers::*;
8use netlink_packet_utils::traits::*;
9use netlink_packet_utils::DecodeError;
10use std::convert::TryFrom;
11use std::mem::{size_of, size_of_val};
12
13// PolicyAttr
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct PolicyAttr {
17    pub index: u16,
18    pub attr_policy: AttributePolicyAttr,
19}
20
21impl Nla for PolicyAttr {
22    fn value_len(&self) -> usize {
23        self.attr_policy.buffer_len()
24    }
25
26    fn kind(&self) -> u16 {
27        self.index
28    }
29
30    fn emit_value(&self, buffer: &mut [u8]) {
31        self.attr_policy.emit(buffer);
32    }
33
34    fn is_nested(&self) -> bool {
35        true
36    }
37}
38
39impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for PolicyAttr {
40    type Error = DecodeError;
41    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
42        let payload = buf.value();
43
44        Ok(Self {
45            index: buf.kind(),
46            attr_policy: AttributePolicyAttr::parse(&NlaBuffer::new(payload))
47                .context("failed to parse PolicyAttr")?,
48        })
49    }
50}
51
52// AttributePolicyAttr
53
54#[derive(Clone, Debug, PartialEq, Eq)]
55pub struct AttributePolicyAttr {
56    pub index: u16,
57    pub policies: Vec<NlPolicyTypeAttrs>,
58}
59
60impl Nla for AttributePolicyAttr {
61    fn value_len(&self) -> usize {
62        self.policies.as_slice().buffer_len()
63    }
64
65    fn kind(&self) -> u16 {
66        self.index
67    }
68
69    fn emit_value(&self, buffer: &mut [u8]) {
70        self.policies.as_slice().emit(buffer);
71    }
72
73    fn is_nested(&self) -> bool {
74        true
75    }
76}
77
78impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for AttributePolicyAttr {
79    type Error = DecodeError;
80    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
81        let payload = buf.value();
82        let policies = NlasIterator::new(payload)
83            .map(|nla| {
84                nla.map_err(|err| DecodeError::from(err))
85                    .and_then(|nla| NlPolicyTypeAttrs::parse(&nla))
86            })
87            .collect::<Result<Vec<_>, _>>()
88            .context("failed to parse AttributePolicyAttr")?;
89
90        Ok(Self { index: buf.kind(), policies })
91    }
92}
93
94// PolicyTypeAttrs
95
96#[derive(Clone, Debug, PartialEq, Eq)]
97pub enum NlPolicyTypeAttrs {
98    Type(NlaType),
99    MinValueSigned(i64),
100    MaxValueSigned(i64),
101    MaxValueUnsigned(u64),
102    MinValueUnsigned(u64),
103    MinLength(u32),
104    MaxLength(u32),
105    PolicyIdx(u32),
106    PolicyMaxType(u32),
107    Bitfield32Mask(u32),
108    Mask(u64),
109}
110
111impl Nla for NlPolicyTypeAttrs {
112    fn value_len(&self) -> usize {
113        use NlPolicyTypeAttrs::*;
114        match self {
115            Type(v) => size_of_val(v),
116            MinValueSigned(v) => size_of_val(v),
117            MaxValueSigned(v) => size_of_val(v),
118            MaxValueUnsigned(v) => size_of_val(v),
119            MinValueUnsigned(v) => size_of_val(v),
120            MinLength(v) => size_of_val(v),
121            MaxLength(v) => size_of_val(v),
122            PolicyIdx(v) => size_of_val(v),
123            PolicyMaxType(v) => size_of_val(v),
124            Bitfield32Mask(v) => size_of_val(v),
125            Mask(v) => size_of_val(v),
126        }
127    }
128
129    fn kind(&self) -> u16 {
130        use NlPolicyTypeAttrs::*;
131        match self {
132            Type(_) => NL_POLICY_TYPE_ATTR_TYPE,
133            MinValueSigned(_) => NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
134            MaxValueSigned(_) => NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
135            MaxValueUnsigned(_) => NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
136            MinValueUnsigned(_) => NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
137            MinLength(_) => NL_POLICY_TYPE_ATTR_MIN_LENGTH,
138            MaxLength(_) => NL_POLICY_TYPE_ATTR_MAX_LENGTH,
139            PolicyIdx(_) => NL_POLICY_TYPE_ATTR_POLICY_IDX,
140            PolicyMaxType(_) => NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
141            Bitfield32Mask(_) => NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
142            Mask(_) => NL_POLICY_TYPE_ATTR_MASK,
143        }
144    }
145
146    fn emit_value(&self, buffer: &mut [u8]) {
147        use NlPolicyTypeAttrs::*;
148        match self {
149            Type(v) => NativeEndian::write_u32(buffer, u32::from(*v)),
150            MinValueSigned(v) => NativeEndian::write_i64(buffer, *v),
151            MaxValueSigned(v) => NativeEndian::write_i64(buffer, *v),
152            MaxValueUnsigned(v) => NativeEndian::write_u64(buffer, *v),
153            MinValueUnsigned(v) => NativeEndian::write_u64(buffer, *v),
154            MinLength(v) => NativeEndian::write_u32(buffer, *v),
155            MaxLength(v) => NativeEndian::write_u32(buffer, *v),
156            PolicyIdx(v) => NativeEndian::write_u32(buffer, *v),
157            PolicyMaxType(v) => NativeEndian::write_u32(buffer, *v),
158            Bitfield32Mask(v) => NativeEndian::write_u32(buffer, *v),
159            Mask(v) => NativeEndian::write_u64(buffer, *v),
160        }
161    }
162}
163
164impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for NlPolicyTypeAttrs {
165    type Error = DecodeError;
166    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
167        let payload = buf.value();
168        Ok(match buf.kind() {
169            NL_POLICY_TYPE_ATTR_TYPE => {
170                let value = parse_u32(payload).context("invalid NL_POLICY_TYPE_ATTR_TYPE value")?;
171                Self::Type(NlaType::try_from(value)?)
172            }
173            NL_POLICY_TYPE_ATTR_MIN_VALUE_S => Self::MinValueSigned(
174                parse_i64(payload).context("invalid NL_POLICY_TYPE_ATTR_MIN_VALUE_S value")?,
175            ),
176            NL_POLICY_TYPE_ATTR_MAX_VALUE_S => Self::MaxValueSigned(
177                parse_i64(payload).context("invalid NL_POLICY_TYPE_ATTR_MAX_VALUE_S value")?,
178            ),
179            NL_POLICY_TYPE_ATTR_MIN_VALUE_U => Self::MinValueUnsigned(
180                parse_u64(payload).context("invalid NL_POLICY_TYPE_ATTR_MIN_VALUE_U value")?,
181            ),
182            NL_POLICY_TYPE_ATTR_MAX_VALUE_U => Self::MaxValueUnsigned(
183                parse_u64(payload).context("invalid NL_POLICY_TYPE_ATTR_MAX_VALUE_U value")?,
184            ),
185            NL_POLICY_TYPE_ATTR_MIN_LENGTH => Self::MinLength(
186                parse_u32(payload).context("invalid NL_POLICY_TYPE_ATTR_MIN_LENGTH value")?,
187            ),
188            NL_POLICY_TYPE_ATTR_MAX_LENGTH => Self::MaxLength(
189                parse_u32(payload).context("invalid NL_POLICY_TYPE_ATTR_MAX_LENGTH value")?,
190            ),
191            NL_POLICY_TYPE_ATTR_POLICY_IDX => Self::PolicyIdx(
192                parse_u32(payload).context("invalid NL_POLICY_TYPE_ATTR_POLICY_IDX value")?,
193            ),
194            NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE => Self::PolicyMaxType(
195                parse_u32(payload).context("invalid NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE value")?,
196            ),
197            NL_POLICY_TYPE_ATTR_BITFIELD32_MASK => Self::Bitfield32Mask(
198                parse_u32(payload).context("invalid NL_POLICY_TYPE_ATTR_BITFIELD32_MASK value")?,
199            ),
200            NL_POLICY_TYPE_ATTR_MASK => {
201                Self::Mask(parse_u64(payload).context("invalid NL_POLICY_TYPE_ATTR_MASK value")?)
202            }
203            kind => return Err(DecodeError::from(format!("Unknown NLA type: {kind}"))),
204        })
205    }
206}
207
208#[derive(Copy, Clone, Debug, PartialEq, Eq)]
209pub enum NlaType {
210    Flag,
211    U8,
212    U16,
213    U32,
214    U64,
215    S8,
216    S16,
217    S32,
218    S64,
219    Binary,
220    String,
221    NulString,
222    Nested,
223    NestedArray,
224    Bitfield32,
225}
226
227impl From<NlaType> for u32 {
228    fn from(nlatype: NlaType) -> u32 {
229        match nlatype {
230            NlaType::Flag => NL_ATTR_TYPE_FLAG,
231            NlaType::U8 => NL_ATTR_TYPE_U8,
232            NlaType::U16 => NL_ATTR_TYPE_U16,
233            NlaType::U32 => NL_ATTR_TYPE_U32,
234            NlaType::U64 => NL_ATTR_TYPE_U64,
235            NlaType::S8 => NL_ATTR_TYPE_S8,
236            NlaType::S16 => NL_ATTR_TYPE_S16,
237            NlaType::S32 => NL_ATTR_TYPE_S32,
238            NlaType::S64 => NL_ATTR_TYPE_S64,
239            NlaType::Binary => NL_ATTR_TYPE_BINARY,
240            NlaType::String => NL_ATTR_TYPE_STRING,
241            NlaType::NulString => NL_ATTR_TYPE_NUL_STRING,
242            NlaType::Nested => NL_ATTR_TYPE_NESTED,
243            NlaType::NestedArray => NL_ATTR_TYPE_NESTED_ARRAY,
244            NlaType::Bitfield32 => NL_ATTR_TYPE_BITFIELD32,
245        }
246    }
247}
248
249impl TryFrom<u32> for NlaType {
250    type Error = DecodeError;
251
252    fn try_from(value: u32) -> Result<Self, Self::Error> {
253        Ok(match value {
254            NL_ATTR_TYPE_FLAG => NlaType::Flag,
255            NL_ATTR_TYPE_U8 => NlaType::U8,
256            NL_ATTR_TYPE_U16 => NlaType::U16,
257            NL_ATTR_TYPE_U32 => NlaType::U32,
258            NL_ATTR_TYPE_U64 => NlaType::U64,
259            NL_ATTR_TYPE_S8 => NlaType::S8,
260            NL_ATTR_TYPE_S16 => NlaType::S16,
261            NL_ATTR_TYPE_S32 => NlaType::S32,
262            NL_ATTR_TYPE_S64 => NlaType::S64,
263            NL_ATTR_TYPE_BINARY => NlaType::Binary,
264            NL_ATTR_TYPE_STRING => NlaType::String,
265            NL_ATTR_TYPE_NUL_STRING => NlaType::NulString,
266            NL_ATTR_TYPE_NESTED => NlaType::Nested,
267            NL_ATTR_TYPE_NESTED_ARRAY => NlaType::NestedArray,
268            NL_ATTR_TYPE_BITFIELD32 => NlaType::Bitfield32,
269            _ => return Err(DecodeError::from(format!("invalid NLA type: {value}"))),
270        })
271    }
272}
273
274// FIXME: Add this into netlink_packet_utils::parser
275fn parse_i64(payload: &[u8]) -> Result<i64, DecodeError> {
276    if payload.len() != size_of::<i64>() {
277        return Err(format!("invalid i64: {payload:?}").into());
278    }
279    Ok(NativeEndian::read_i64(payload))
280}