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