1use std::io::Cursor;
16
17use derive_builder::{Builder, UninitializedFieldError};
18use getset::Getters;
19
20use crate::{
21 self as neli, FromBytes, FromBytesWithInput, FromBytesWithInputBorrowed, Header, Size, ToBytes,
22 TypeSize,
23 attr::{AttrHandle, Attribute},
24 consts::genl::{Cmd, NlAttrType},
25 err::{DeError, SerError},
26 types::{Buffer, GenlBuffer},
27};
28
29#[derive(Clone, Debug, PartialEq, Eq, Size, ToBytes, FromBytes)]
31pub struct NoUserHeader;
32
33impl TypeSize for NoUserHeader {
34 fn type_size() -> usize {
35 0
36 }
37}
38
39#[derive(
41 Builder, Getters, Clone, Debug, PartialEq, Eq, Size, ToBytes, FromBytesWithInput, Header,
42)]
43#[neli(to_bytes_bound = "C: Cmd")]
44#[neli(to_bytes_bound = "T: NlAttrType")]
45#[neli(from_bytes_bound = "C: Cmd + TypeSize")]
46#[neli(from_bytes_bound = "T: NlAttrType")]
47#[neli(header_bound = "C: TypeSize")]
48#[neli(from_bytes_bound = "H: TypeSize + FromBytes")]
49#[neli(header_bound = "H: TypeSize")]
50#[builder(pattern = "owned")]
51#[builder(build_fn(skip))]
52pub struct Genlmsghdr<C, T, H = NoUserHeader> {
53 #[getset(get = "pub")]
55 cmd: C,
56 #[getset(get = "pub")]
58 version: u8,
59 #[builder(setter(skip))]
60 reserved: u16,
61 #[getset(get = "pub")]
64 header: H,
65 #[getset(get = "pub")]
67 #[neli(input = "input.checked_sub(Self::header_size()).ok_or(DeError::InvalidInput(input))?")]
68 attrs: GenlBuffer<T, Buffer>,
69}
70
71impl<C, T> GenlmsghdrBuilder<C, T, NoUserHeader> {
72 pub fn build(self) -> Result<Genlmsghdr<C, T>, GenlmsghdrBuilderError> {
74 let cmd = self
75 .cmd
76 .ok_or_else(|| GenlmsghdrBuilderError::from(UninitializedFieldError::new("cmd")))?;
77 let version = self
78 .version
79 .ok_or_else(|| GenlmsghdrBuilderError::from(UninitializedFieldError::new("version")))?;
80 let reserved = 0;
81 let header = self.header.unwrap_or(NoUserHeader);
82 let attrs = self.attrs.unwrap_or_default();
83
84 Ok(Genlmsghdr {
85 cmd,
86 version,
87 reserved,
88 header,
89 attrs,
90 })
91 }
92}
93
94impl<C, T, H> GenlmsghdrBuilder<C, T, H> {
95 pub fn build_with_header(self) -> Result<Genlmsghdr<C, T, H>, GenlmsghdrBuilderError> {
97 let cmd = self
98 .cmd
99 .ok_or_else(|| GenlmsghdrBuilderError::from(UninitializedFieldError::new("cmd")))?;
100 let version = self
101 .version
102 .ok_or_else(|| GenlmsghdrBuilderError::from(UninitializedFieldError::new("version")))?;
103 let reserved = 0;
104 let header = self
105 .header
106 .ok_or_else(|| GenlmsghdrBuilderError::from(UninitializedFieldError::new("header")))?;
107 let attrs = self.attrs.unwrap_or_default();
108
109 Ok(Genlmsghdr {
110 cmd,
111 version,
112 reserved,
113 header,
114 attrs,
115 })
116 }
117}
118
119#[derive(Builder, Getters, Debug, PartialEq, Eq, Clone)]
122#[builder(pattern = "owned")]
123pub struct AttrType<T> {
124 #[getset(get = "pub")]
126 #[builder(default = "false")]
127 nla_nested: bool,
128 #[getset(get = "pub")]
130 #[builder(default = "false")]
131 nla_network_order: bool,
132 #[getset(get = "pub")]
134 nla_type: T,
135}
136
137impl<T> Size for AttrType<T>
138where
139 T: Size,
140{
141 fn unpadded_size(&self) -> usize {
142 self.nla_type.unpadded_size()
143 }
144}
145
146impl<T> TypeSize for AttrType<T>
147where
148 T: TypeSize,
149{
150 fn type_size() -> usize {
151 T::type_size()
152 }
153}
154
155impl<T> ToBytes for AttrType<T>
156where
157 T: NlAttrType,
158{
159 fn to_bytes(&self, buffer: &mut Cursor<Vec<u8>>) -> Result<(), SerError> {
160 let int: u16 = self.into();
161 int.to_bytes(buffer)
162 }
163}
164
165impl<T> FromBytes for AttrType<T>
166where
167 T: NlAttrType,
168{
169 fn from_bytes(buffer: &mut Cursor<impl AsRef<[u8]>>) -> Result<Self, DeError> {
170 let int = u16::from_bytes(buffer)?;
171 Ok(AttrType::from(int))
172 }
173}
174
175impl<T> From<AttrType<T>> for u16
176where
177 T: NlAttrType,
178{
179 fn from(v: AttrType<T>) -> Self {
180 let mut int: u16 = v.nla_type.into();
181 int |= u16::from(v.nla_nested) << 15;
182 int |= u16::from(v.nla_network_order) << 14;
183 int
184 }
185}
186
187impl<'a, T> From<&'a AttrType<T>> for u16
188where
189 T: NlAttrType,
190{
191 fn from(v: &'a AttrType<T>) -> Self {
192 let mut int: u16 = v.nla_type.into();
193 int |= u16::from(v.nla_nested) << 15;
194 int |= u16::from(v.nla_network_order) << 14;
195 int
196 }
197}
198
199impl<T> From<u16> for AttrType<T>
200where
201 T: NlAttrType,
202{
203 fn from(int: u16) -> Self {
204 AttrType {
205 nla_nested: (int & 1 << 15) == (1 << 15),
206 nla_network_order: (int & 1 << 14) == (1 << 14),
207 nla_type: T::from(!(3 << 14) & int),
208 }
209 }
210}
211
212#[derive(Builder, Getters, Clone, Debug, PartialEq, Eq, Size, FromBytes, ToBytes, Header)]
214#[neli(from_bytes_bound = "T: NlAttrType")]
215#[neli(from_bytes_bound = "P: FromBytesWithInput<Input = usize>")]
216#[neli(to_bytes_bound = "T: NlAttrType")]
217#[neli(header_bound = "T: TypeSize")]
218#[neli(padding)]
219#[builder(pattern = "owned")]
220#[builder(build_fn(skip))]
221pub struct Nlattr<T, P> {
222 #[getset(get = "pub")]
224 #[builder(setter(skip))]
225 nla_len: u16,
226 #[getset(get = "pub")]
228 nla_type: AttrType<T>,
229 #[neli(
231 input = "(nla_len as usize).checked_sub(Self::header_size()).ok_or(DeError::InvalidInput(nla_len as usize))?"
232 )]
233 #[getset(get = "pub")]
234 nla_payload: P,
235}
236
237impl<T, P> NlattrBuilder<T, P>
238where
239 T: Size,
240 P: Size + ToBytes,
241{
242 pub fn build(self) -> Result<Nlattr<T, Buffer>, NlattrBuilderError> {
244 let nla_type = self
245 .nla_type
246 .ok_or_else(|| NlattrBuilderError::from(UninitializedFieldError::new("nla_type")))?;
247 let nla_payload = self
248 .nla_payload
249 .ok_or_else(|| NlattrBuilderError::from(UninitializedFieldError::new("nla_payload")))?;
250 let mut buffer = Cursor::new(vec![0; nla_payload.unpadded_size()]);
251 nla_payload.to_bytes(&mut buffer).map_err(|_| {
252 NlattrBuilderError::ValidationError(
253 "Could not convert payload to binary representation".to_string(),
254 )
255 })?;
256 let mut nlattr = Nlattr {
257 nla_len: 0,
258 nla_type,
259 nla_payload: Buffer::from(buffer.into_inner()),
260 };
261 nlattr.nla_len = nlattr.unpadded_size() as u16;
262 Ok(nlattr)
263 }
264}
265
266impl<T> Nlattr<T, Buffer>
267where
268 T: NlAttrType,
269{
270 #[inline]
274 pub fn nest<TT, P>(mut self, attr: &Nlattr<TT, P>) -> Result<Self, SerError>
275 where
276 TT: NlAttrType,
277 P: ToBytes,
278 {
279 self.add_nested_attribute(attr)?;
280 Ok(self)
281 }
282
283 fn add_nested_attribute<TT, P>(&mut self, attr: &Nlattr<TT, P>) -> Result<(), SerError>
285 where
286 TT: NlAttrType,
287 P: ToBytes,
288 {
289 let mut buffer = Cursor::new(Vec::new());
290 self.nla_type.nla_nested = true;
291 attr.to_bytes(&mut buffer)?;
292
293 self.nla_payload.extend_from_slice(buffer.get_ref());
294 self.nla_len += buffer.get_ref().len() as u16;
295 Ok(())
296 }
297
298 pub fn get_attr_handle<R>(&self) -> Result<GenlAttrHandle<R>, DeError>
300 where
301 R: NlAttrType,
302 {
303 Ok(AttrHandle::new(GenlBuffer::from_bytes_with_input(
304 &mut Cursor::new(self.nla_payload.as_ref()),
305 self.nla_payload.unpadded_size(),
306 )?))
307 }
308}
309
310impl<T> Attribute<T> for Nlattr<T, Buffer>
311where
312 T: NlAttrType,
313{
314 fn payload(&self) -> &Buffer {
315 &self.nla_payload
316 }
317
318 fn set_payload<P>(&mut self, payload: &P) -> Result<(), SerError>
319 where
320 P: Size + ToBytes,
321 {
322 let mut buffer = Cursor::new(Vec::new());
323 payload.to_bytes(&mut buffer)?;
324
325 self.nla_len -= self.nla_payload.unpadded_size() as u16;
327 self.nla_len += buffer.get_ref().len() as u16;
328
329 self.nla_payload = Buffer::from(buffer.into_inner());
330
331 Ok(())
332 }
333}
334
335pub type GenlAttrHandle<'a, T> = AttrHandle<'a, GenlBuffer<T, Buffer>, Nlattr<T, Buffer>>;
337
338impl<'a, T> GenlAttrHandle<'a, T>
339where
340 T: NlAttrType,
341{
342 pub fn get_nested_attributes<S>(&self, subattr: T) -> Result<GenlAttrHandle<S>, DeError>
345 where
346 S: NlAttrType,
347 {
348 let attr = self
349 .get_attribute(subattr)
350 .ok_or_else(|| DeError::new("Couldn't find specified attribute"))?;
351 Ok(AttrHandle::new(GenlBuffer::from_bytes_with_input(
352 &mut Cursor::new(attr.nla_payload.as_ref()),
353 attr.nla_payload.unpadded_size(),
354 )?))
355 }
356
357 pub fn get_attribute(&self, t: T) -> Option<&Nlattr<T, Buffer>> {
359 self.get_attrs()
360 .iter()
361 .find(|item| item.nla_type.nla_type == t)
362 }
363
364 pub fn get_attr_payload_as<R>(&self, attr: T) -> Result<R, DeError>
366 where
367 R: FromBytes,
368 {
369 match self.get_attribute(attr) {
370 Some(a) => a.get_payload_as::<R>(),
371 _ => Err(DeError::new("Failed to find specified attribute")),
372 }
373 }
374
375 pub fn get_attr_payload_as_with_len<R>(&self, attr: T) -> Result<R, DeError>
378 where
379 R: FromBytesWithInput<Input = usize>,
380 {
381 match self.get_attribute(attr) {
382 Some(a) => a.get_payload_as_with_len::<R>(),
383 _ => Err(DeError::new("Failed to find specified attribute")),
384 }
385 }
386
387 pub fn get_attr_payload_as_with_len_borrowed<R>(&'a self, attr: T) -> Result<R, DeError>
390 where
391 R: FromBytesWithInputBorrowed<'a, Input = usize>,
392 {
393 match self.get_attribute(attr) {
394 Some(a) => a.get_payload_as_with_len_borrowed::<R>(),
395 _ => Err(DeError::new("Failed to find specified attribute")),
396 }
397 }
398}