1use std::fmt;
2
3pub use crate::primitives::*;
4pub use std::{ffi::CStr, fmt::Debug, iter::Iterator};
5
6pub fn dump_hex(buf: &[u8]) {
7 let mut len = 0;
8 for chunk in buf.chunks(16) {
9 print!("{len:04x?}: ");
10 print!("{chunk:02x?} ");
11 for b in chunk {
12 if b.is_ascii() && !b.is_ascii_control() {
13 print!("{}", char::from_u32(*b as u32).unwrap());
14 } else {
15 print!(".");
16 }
17 }
18 println!();
19 len += chunk.len();
20 }
21}
22
23pub fn dump_assert_eq(left: &[u8], right: &[u8]) {
24 if left.len() != right.len() {
25 dump_hex(left);
26 dump_hex(right);
27 panic!("Length mismatched");
28 }
29 if let Some(pos) = left.iter().zip(right.iter()).position(|(l, r)| *l != *r) {
30 println!();
31 println!("Left:");
32 dump_hex(left);
33 println!();
34 println!("Right:");
35 dump_hex(right);
36 panic!("Differ at byte {pos} (0x{pos:x?})");
37 }
38}
39
40pub struct FormatHex<'a>(pub &'a [u8]);
41
42impl Debug for FormatHex<'_> {
43 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
44 write!(fmt, "\"")?;
45 for i in self.0 {
46 write!(fmt, "{i:02x}")?
47 }
48 write!(fmt, "\"")?;
49 Ok(())
50 }
51}
52
53pub struct FormatEnum<T: Debug>(pub u64, pub fn(u64) -> Option<T>);
54
55impl<T: Debug> Debug for FormatEnum<T> {
56 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
57 write!(fmt, "{} ", self.0)?;
58
59 if let Some(var) = (self.1)(self.0) {
60 write!(fmt, "[{var:?}]")?;
61 } else {
62 write!(fmt, "(unknown variant)")?;
63 }
64
65 Ok(())
66 }
67}
68
69pub struct FormatFlags<T: Debug>(pub u64, pub fn(u64) -> Option<T>);
70
71impl<T: Debug> Debug for FormatFlags<T> {
72 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(fmt, "{} ", self.0)?;
74
75 if self.0 == 0 {
76 write!(fmt, "(empty)")?;
77 return Ok(());
78 }
79
80 let mut seen_variant = false;
81 for i in 0..u64::BITS {
82 let bit = self.0 & (1 << i);
83 if bit == 0 {
84 continue;
85 }
86
87 if !seen_variant {
88 seen_variant = true;
89 write!(fmt, "[")?;
90 } else {
91 write!(fmt, ",")?;
92 }
93
94 if let Some(var) = (self.1)(bit) {
95 write!(fmt, "{var:?}")?;
96 } else {
97 write!(fmt, "(unknown bit {i})")?;
98 }
99 }
100
101 if seen_variant {
102 write!(fmt, "]")?;
103 }
104
105 Ok(())
106 }
107}
108
109pub struct DisplayAsDebug<T>(T);
110
111impl<T: fmt::Display> fmt::Debug for DisplayAsDebug<T> {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(f, "{}", self.0)
114 }
115}
116
117pub struct FlattenErrorContext<T: fmt::Debug>(pub Result<T, ErrorContext>);
118
119impl<T: Debug> fmt::Debug for FlattenErrorContext<T> {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 match &self.0 {
122 Ok(ok) => ok.fmt(f),
123 Err(err) => {
124 f.write_str("Err(")?;
125 err.fmt(f)?;
126 f.write_str(")")
127 }
128 }
129 }
130}
131
132pub struct MapFormatArray<I, T, M, D>(pub T, pub M)
133where
134 T: Clone + Iterator<Item = Result<I, ErrorContext>>,
135 M: Clone + FnMut(I) -> D,
136 D: fmt::Debug;
137
138impl<I, T, M, D> fmt::Debug for MapFormatArray<I, T, M, D>
139where
140 T: Clone + Iterator<Item = Result<I, ErrorContext>>,
141 M: Clone + FnMut(I) -> D,
142 D: fmt::Debug,
143{
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 let mut f = f.debug_list();
146 for item in self.0.clone() {
147 f.entry(&FlattenErrorContext(item.map(self.1.clone())));
148 }
149 f.finish()
150 }
151}
152
153pub const NLA_F_NESTED: u16 = 1 << 15;
154pub const NLA_F_NET_BYTEORDER: u16 = 1 << 14;
155
156pub const fn nla_type(r#type: u16) -> u16 {
157 r#type & (!(NLA_F_NESTED | NLA_F_NET_BYTEORDER))
158}
159
160pub const NLA_ALIGNTO: usize = 4;
161
162pub const fn nla_align_up(len: usize) -> usize {
163 ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
164}
165
166pub fn align(buf: &mut Vec<u8>) {
167 let len = buf.len();
168 buf.extend(std::iter::repeat_n(0u8, nla_align_up(len) - len));
169}
170
171pub fn push_nested_header(buf: &mut Vec<u8>, r#type: u16) -> usize {
173 push_header_type(buf, r#type, 0, true)
174}
175
176pub fn push_header(buf: &mut Vec<u8>, r#type: u16, len: u16) -> usize {
178 push_header_type(buf, r#type, len, false)
179}
180
181fn push_header_type(buf: &mut Vec<u8>, mut r#type: u16, len: u16, is_nested: bool) -> usize {
184 align(buf);
185
186 let header_offset = buf.len();
187
188 if is_nested {
189 r#type |= NLA_F_NESTED;
190 }
191
192 buf.extend((len + 4).to_ne_bytes());
194 buf.extend(r#type.to_ne_bytes());
195
196 align(buf);
197
198 header_offset
199}
200
201pub fn finalize_nested_header(buf: &mut Vec<u8>, offset: usize) {
202 align(buf);
203
204 let len = (buf.len() - offset) as u16;
205 buf[offset..(offset + 2)].copy_from_slice(&len.to_ne_bytes());
206}
207
208#[derive(Debug, Clone, Copy)]
209pub struct Header {
210 pub r#type: u16,
211 pub is_nested: bool,
212}
213
214pub fn chop_header<'a>(buf: &'a [u8], pos: &mut usize) -> Option<(Header, &'a [u8])> {
215 let buf = &buf[*pos..];
216
217 if buf.len() < 4 {
218 return None;
219 }
220
221 let len = parse_u16(&buf[0..2]).unwrap();
222 let r#type = parse_u16(&buf[2..4]).unwrap();
223
224 let next_len = nla_align_up(len as usize);
225
226 if len < 4 || buf.len() < len as usize {
227 return None;
228 }
229
230 let next = &buf[4..len as usize];
231 *pos += next_len.min(buf.len());
232
233 Some((
234 Header {
235 r#type: nla_type(r#type),
236 is_nested: r#type & NLA_F_NESTED != 0,
237 },
238 next,
239 ))
240}
241
242pub trait Rec {
243 fn as_rec_mut(&mut self) -> &mut Vec<u8>;
244}
245
246impl Rec for &mut Vec<u8> {
247 fn as_rec_mut(&mut self) -> &mut Vec<u8> {
248 self
249 }
250}
251
252#[derive(Debug, Clone, PartialEq, Eq)]
253pub enum ErrorReason {
254 AttrMissing,
256 ParsingError,
258 UnknownAttr,
260}
261
262#[derive(Clone, PartialEq, Eq)]
263pub struct ErrorContext {
264 pub attrs: &'static str,
265 pub attr: Option<&'static str>,
266 pub offset: usize,
267 pub reason: ErrorReason,
268}
269
270impl std::error::Error for ErrorContext {}
271
272impl From<ErrorContext> for std::io::Error {
273 fn from(value: ErrorContext) -> Self {
274 Self::other(value)
275 }
276}
277
278impl fmt::Debug for ErrorContext {
279 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280 f.debug_struct("ErrorContext")
281 .field("message", &DisplayAsDebug(&self))
282 .field("reason", &self.reason)
283 .field("attrs", &self.attrs)
284 .field("attr", &self.attr)
285 .field("offset", &self.offset)
286 .finish()
287 }
288}
289
290impl fmt::Display for ErrorContext {
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 let attrs = self.attrs;
293 if matches!(self.reason, ErrorReason::AttrMissing) {
294 let attr = self.attr.unwrap();
295 write!(f, "Missing attribute {attr:?} in {attrs:?}")?;
296 return Ok(());
297 } else {
298 write!(f, "Error parsing ")?;
299 if let Some(attr) = self.attr {
300 write!(f, "attribute {attr:?} of {attrs:?}")?;
301 } else {
302 write!(f, "header of {attrs:?}")?;
303 if matches!(self.reason, ErrorReason::UnknownAttr) {
304 write!(f, " (unknown attribute)")?;
305 }
306 }
307 }
308 write!(f, " at offset {}", self.offset)?;
309 Ok(())
310 }
311}
312
313impl ErrorContext {
314 #[cold]
315 pub(crate) fn new(
316 attrs: &'static str,
317 attr: Option<&'static str>,
318 orig_loc: usize,
319 loc: usize,
320 ) -> ErrorContext {
321 let ctx = ErrorContext {
322 attrs,
323 attr,
324 offset: Self::calc_offset(orig_loc, loc),
325 reason: if attr.is_some() {
326 ErrorReason::ParsingError
327 } else {
328 ErrorReason::UnknownAttr
329 },
330 };
331
332 if cfg!(test) {
333 panic!("{ctx}")
334 } else {
335 ctx
336 }
337 }
338
339 #[cold]
340 pub(crate) fn new_missing(
341 attrs: &'static str,
342 attr: &'static str,
343 orig_loc: usize,
344 loc: usize,
345 ) -> ErrorContext {
346 let ctx = ErrorContext {
347 attrs,
348 attr: Some(attr),
349 offset: Self::calc_offset(orig_loc, loc),
350 reason: ErrorReason::AttrMissing,
351 };
352
353 if cfg!(test) {
354 panic!("{ctx}")
355 } else {
356 ctx
357 }
358 }
359
360 pub(crate) fn calc_offset(orig_loc: usize, loc: usize) -> usize {
361 if orig_loc <= loc && loc - orig_loc <= u16::MAX as usize {
362 loc - orig_loc
363 } else {
364 0
365 }
366 }
367}
368
369#[derive(Clone)]
370pub struct MultiAttrIterable<I, T, V>
371where
372 I: Iterator<Item = Result<T, ErrorContext>>,
373{
374 pub(crate) inner: I,
375 pub(crate) f: fn(T) -> Option<V>,
376}
377
378impl<I, T, V> MultiAttrIterable<I, T, V>
379where
380 I: Iterator<Item = Result<T, ErrorContext>>,
381{
382 pub fn new(inner: I, f: fn(T) -> Option<V>) -> Self {
383 Self { inner, f }
384 }
385}
386
387impl<I, T, V> Iterator for MultiAttrIterable<I, T, V>
388where
389 I: Iterator<Item = Result<T, ErrorContext>>,
390{
391 type Item = V;
392 fn next(&mut self) -> Option<Self::Item> {
393 match self.inner.next() {
394 Some(Ok(val)) => (self.f)(val),
395 _ => None,
396 }
397 }
398}
399
400#[derive(Clone)]
401pub struct ArrayIterable<I, T>
402where
403 I: Iterator<Item = Result<T, ErrorContext>>,
404{
405 pub(crate) inner: I,
406}
407
408impl<I, T> ArrayIterable<I, T>
409where
410 I: Iterator<Item = Result<T, ErrorContext>>,
411{
412 pub fn new(inner: I) -> Self {
413 Self { inner }
414 }
415}
416
417impl<I, T> Iterator for ArrayIterable<I, T>
418where
419 I: Iterator<Item = Result<T, ErrorContext>>,
420{
421 type Item = T;
422 fn next(&mut self) -> Option<Self::Item> {
423 match self.inner.next() {
424 Some(Ok(val)) => Some(val),
425 _ => None,
426 }
427 }
428}
429
430#[derive(Debug)]
431pub enum RequestBuf<'a> {
432 Ref(&'a mut Vec<u8>),
433 Own(Vec<u8>),
434}
435
436impl RequestBuf<'_> {
437 pub fn buf(&self) -> &Vec<u8> {
438 match self {
439 RequestBuf::Ref(buf) => buf,
440 RequestBuf::Own(buf) => buf,
441 }
442 }
443
444 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
445 match self {
446 RequestBuf::Ref(buf) => buf,
447 RequestBuf::Own(buf) => buf,
448 }
449 }
450}
451
452impl Rec for RequestBuf<'_> {
453 fn as_rec_mut(&mut self) -> &mut Vec<u8> {
454 self.buf_mut()
455 }
456}