Skip to main content

netlink_bindings/unix-diag/
mod.rs

1#![doc = "UNIX socket diagnostics\n"]
2#![allow(clippy::all)]
3#![allow(unused_imports)]
4#![allow(unused_assignments)]
5#![allow(non_snake_case)]
6#![allow(unused_variables)]
7#![allow(irrefutable_let_patterns)]
8#![allow(unreachable_code)]
9#![allow(unreachable_patterns)]
10use crate::builtin::{BuiltinBitfield32, BuiltinNfgenmsg, Nlmsghdr, PushDummy};
11use crate::{
12    consts,
13    traits::{NetlinkRequest, Protocol},
14    utils::*,
15};
16pub const PROTONAME: &str = "unix-diag";
17pub const PROTONAME_CSTR: &CStr = c"unix-diag";
18pub const PROTONUM: u16 = 4u16;
19#[doc = "VFS inode info"]
20#[doc = "Receive queue length info"]
21#[doc = "Flags - defines an integer enumeration, with values for each entry occupying a bit, starting from bit 0, (e.g. 1, 2, 4, 8)"]
22#[derive(Debug, Clone, Copy)]
23pub enum ShowFlags {
24    #[doc = "show name (not path)"]
25    Name = 1 << 0,
26    #[doc = "show VFS inode info"]
27    Vfs = 1 << 1,
28    #[doc = "show peer socket info"]
29    Peer = 1 << 2,
30    #[doc = "show pending connections"]
31    Icons = 1 << 3,
32    #[doc = "show skb receive queue len"]
33    Rqlen = 1 << 4,
34    #[doc = "show memory info of a socket"]
35    Meminfo = 1 << 5,
36    #[doc = "show socket's UID"]
37    Uid = 1 << 6,
38}
39impl ShowFlags {
40    pub fn from_value(value: u64) -> Option<Self> {
41        Some(match value {
42            n if n == 1 << 0 => Self::Name,
43            n if n == 1 << 1 => Self::Vfs,
44            n if n == 1 << 2 => Self::Peer,
45            n if n == 1 << 3 => Self::Icons,
46            n if n == 1 << 4 => Self::Rqlen,
47            n if n == 1 << 5 => Self::Meminfo,
48            n if n == 1 << 6 => Self::Uid,
49            _ => return None,
50        })
51    }
52}
53#[repr(C, packed(4))]
54pub struct Req {
55    pub sdiag_family: u8,
56    pub sdiag_protocol: u8,
57    pub pad: u16,
58    #[doc = "States to dump"]
59    pub udiag_states: u32,
60    pub udiag_ino: u32,
61    #[doc = "Show flags"]
62    pub udiag_show: u32,
63    pub udiag_cookie: [u8; 8usize],
64}
65impl Clone for Req {
66    fn clone(&self) -> Self {
67        Self::new_from_array(*self.as_array())
68    }
69}
70#[doc = "Create zero-initialized struct"]
71impl Default for Req {
72    fn default() -> Self {
73        Self::new()
74    }
75}
76impl Req {
77    #[doc = "Create zero-initialized struct"]
78    pub fn new() -> Self {
79        Self::new_from_array([0u8; Self::len()])
80    }
81    #[doc = "Copy from contents from slice"]
82    pub fn new_from_slice(other: &[u8]) -> Option<Self> {
83        if other.len() != Self::len() {
84            return None;
85        }
86        let mut buf = [0u8; Self::len()];
87        buf.clone_from_slice(other);
88        Some(Self::new_from_array(buf))
89    }
90    #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
91    pub fn new_from_zeroed(other: &[u8]) -> Self {
92        let mut buf = [0u8; Self::len()];
93        let len = buf.len().min(other.len());
94        buf[..len].clone_from_slice(&other[..len]);
95        Self::new_from_array(buf)
96    }
97    pub fn new_from_array(buf: [u8; 24usize]) -> Self {
98        unsafe { std::mem::transmute(buf) }
99    }
100    pub fn as_slice(&self) -> &[u8] {
101        unsafe {
102            let ptr: *const u8 = std::mem::transmute(self as *const Self);
103            std::slice::from_raw_parts(ptr, Self::len())
104        }
105    }
106    pub fn from_slice(buf: &[u8]) -> &Self {
107        assert!(buf.len() >= Self::len());
108        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
109        unsafe { std::mem::transmute(buf.as_ptr()) }
110    }
111    pub fn as_array(&self) -> &[u8; 24usize] {
112        unsafe { std::mem::transmute(self) }
113    }
114    pub fn from_array(buf: &[u8; 24usize]) -> &Self {
115        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
116        unsafe { std::mem::transmute(buf) }
117    }
118    pub fn into_array(self) -> [u8; 24usize] {
119        unsafe { std::mem::transmute(self) }
120    }
121    pub const fn len() -> usize {
122        const _: () = assert!(std::mem::size_of::<Req>() == 24usize);
123        24usize
124    }
125}
126impl std::fmt::Debug for Req {
127    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        fmt.debug_struct("Req")
129            .field("sdiag_family", &self.sdiag_family)
130            .field("sdiag_protocol", &self.sdiag_protocol)
131            .field("pad", &self.pad)
132            .field("udiag_states", &self.udiag_states)
133            .field("udiag_ino", &self.udiag_ino)
134            .field("udiag_show", &self.udiag_show)
135            .field("udiag_cookie", &FormatHex(self.udiag_cookie))
136            .finish()
137    }
138}
139#[repr(C, packed(4))]
140pub struct Msg {
141    pub udiag_family: u8,
142    pub udiag_type: u8,
143    pub udiag_state: u8,
144    pub pad: u8,
145    pub udiag_ino: u32,
146    pub udiag_cookie: [u8; 8usize],
147}
148impl Clone for Msg {
149    fn clone(&self) -> Self {
150        Self::new_from_array(*self.as_array())
151    }
152}
153#[doc = "Create zero-initialized struct"]
154impl Default for Msg {
155    fn default() -> Self {
156        Self::new()
157    }
158}
159impl Msg {
160    #[doc = "Create zero-initialized struct"]
161    pub fn new() -> Self {
162        Self::new_from_array([0u8; Self::len()])
163    }
164    #[doc = "Copy from contents from slice"]
165    pub fn new_from_slice(other: &[u8]) -> Option<Self> {
166        if other.len() != Self::len() {
167            return None;
168        }
169        let mut buf = [0u8; Self::len()];
170        buf.clone_from_slice(other);
171        Some(Self::new_from_array(buf))
172    }
173    #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
174    pub fn new_from_zeroed(other: &[u8]) -> Self {
175        let mut buf = [0u8; Self::len()];
176        let len = buf.len().min(other.len());
177        buf[..len].clone_from_slice(&other[..len]);
178        Self::new_from_array(buf)
179    }
180    pub fn new_from_array(buf: [u8; 16usize]) -> Self {
181        unsafe { std::mem::transmute(buf) }
182    }
183    pub fn as_slice(&self) -> &[u8] {
184        unsafe {
185            let ptr: *const u8 = std::mem::transmute(self as *const Self);
186            std::slice::from_raw_parts(ptr, Self::len())
187        }
188    }
189    pub fn from_slice(buf: &[u8]) -> &Self {
190        assert!(buf.len() >= Self::len());
191        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
192        unsafe { std::mem::transmute(buf.as_ptr()) }
193    }
194    pub fn as_array(&self) -> &[u8; 16usize] {
195        unsafe { std::mem::transmute(self) }
196    }
197    pub fn from_array(buf: &[u8; 16usize]) -> &Self {
198        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
199        unsafe { std::mem::transmute(buf) }
200    }
201    pub fn into_array(self) -> [u8; 16usize] {
202        unsafe { std::mem::transmute(self) }
203    }
204    pub const fn len() -> usize {
205        const _: () = assert!(std::mem::size_of::<Msg>() == 16usize);
206        16usize
207    }
208}
209impl std::fmt::Debug for Msg {
210    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        fmt.debug_struct("Msg")
212            .field("udiag_family", &self.udiag_family)
213            .field("udiag_type", &self.udiag_type)
214            .field("udiag_state", &self.udiag_state)
215            .field("pad", &self.pad)
216            .field("udiag_ino", &self.udiag_ino)
217            .field("udiag_cookie", &FormatHex(self.udiag_cookie))
218            .finish()
219    }
220}
221#[derive(Debug)]
222#[repr(C, packed(4))]
223pub struct Vfs {
224    pub udiag_vfs_ino: u32,
225    pub udiag_vfs_dev: u32,
226}
227impl Clone for Vfs {
228    fn clone(&self) -> Self {
229        Self::new_from_array(*self.as_array())
230    }
231}
232#[doc = "Create zero-initialized struct"]
233impl Default for Vfs {
234    fn default() -> Self {
235        Self::new()
236    }
237}
238impl Vfs {
239    #[doc = "Create zero-initialized struct"]
240    pub fn new() -> Self {
241        Self::new_from_array([0u8; Self::len()])
242    }
243    #[doc = "Copy from contents from slice"]
244    pub fn new_from_slice(other: &[u8]) -> Option<Self> {
245        if other.len() != Self::len() {
246            return None;
247        }
248        let mut buf = [0u8; Self::len()];
249        buf.clone_from_slice(other);
250        Some(Self::new_from_array(buf))
251    }
252    #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
253    pub fn new_from_zeroed(other: &[u8]) -> Self {
254        let mut buf = [0u8; Self::len()];
255        let len = buf.len().min(other.len());
256        buf[..len].clone_from_slice(&other[..len]);
257        Self::new_from_array(buf)
258    }
259    pub fn new_from_array(buf: [u8; 8usize]) -> Self {
260        unsafe { std::mem::transmute(buf) }
261    }
262    pub fn as_slice(&self) -> &[u8] {
263        unsafe {
264            let ptr: *const u8 = std::mem::transmute(self as *const Self);
265            std::slice::from_raw_parts(ptr, Self::len())
266        }
267    }
268    pub fn from_slice(buf: &[u8]) -> &Self {
269        assert!(buf.len() >= Self::len());
270        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
271        unsafe { std::mem::transmute(buf.as_ptr()) }
272    }
273    pub fn as_array(&self) -> &[u8; 8usize] {
274        unsafe { std::mem::transmute(self) }
275    }
276    pub fn from_array(buf: &[u8; 8usize]) -> &Self {
277        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
278        unsafe { std::mem::transmute(buf) }
279    }
280    pub fn into_array(self) -> [u8; 8usize] {
281        unsafe { std::mem::transmute(self) }
282    }
283    pub const fn len() -> usize {
284        const _: () = assert!(std::mem::size_of::<Vfs>() == 8usize);
285        8usize
286    }
287}
288#[derive(Debug)]
289#[repr(C, packed(4))]
290pub struct Rqlen {
291    pub udiag_rqueue: u32,
292    pub udiag_wqueue: u32,
293}
294impl Clone for Rqlen {
295    fn clone(&self) -> Self {
296        Self::new_from_array(*self.as_array())
297    }
298}
299#[doc = "Create zero-initialized struct"]
300impl Default for Rqlen {
301    fn default() -> Self {
302        Self::new()
303    }
304}
305impl Rqlen {
306    #[doc = "Create zero-initialized struct"]
307    pub fn new() -> Self {
308        Self::new_from_array([0u8; Self::len()])
309    }
310    #[doc = "Copy from contents from slice"]
311    pub fn new_from_slice(other: &[u8]) -> Option<Self> {
312        if other.len() != Self::len() {
313            return None;
314        }
315        let mut buf = [0u8; Self::len()];
316        buf.clone_from_slice(other);
317        Some(Self::new_from_array(buf))
318    }
319    #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
320    pub fn new_from_zeroed(other: &[u8]) -> Self {
321        let mut buf = [0u8; Self::len()];
322        let len = buf.len().min(other.len());
323        buf[..len].clone_from_slice(&other[..len]);
324        Self::new_from_array(buf)
325    }
326    pub fn new_from_array(buf: [u8; 8usize]) -> Self {
327        unsafe { std::mem::transmute(buf) }
328    }
329    pub fn as_slice(&self) -> &[u8] {
330        unsafe {
331            let ptr: *const u8 = std::mem::transmute(self as *const Self);
332            std::slice::from_raw_parts(ptr, Self::len())
333        }
334    }
335    pub fn from_slice(buf: &[u8]) -> &Self {
336        assert!(buf.len() >= Self::len());
337        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
338        unsafe { std::mem::transmute(buf.as_ptr()) }
339    }
340    pub fn as_array(&self) -> &[u8; 8usize] {
341        unsafe { std::mem::transmute(self) }
342    }
343    pub fn from_array(buf: &[u8; 8usize]) -> &Self {
344        assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
345        unsafe { std::mem::transmute(buf) }
346    }
347    pub fn into_array(self) -> [u8; 8usize] {
348        unsafe { std::mem::transmute(self) }
349    }
350    pub const fn len() -> usize {
351        const _: () = assert!(std::mem::size_of::<Rqlen>() == 8usize);
352        8usize
353    }
354}
355#[derive(Clone)]
356pub enum UnixDiagAttrs<'a> {
357    #[doc = "Unix socket sun\\_path\\. May or may not contain '\\\\0'\\."]
358    Name(&'a [u8]),
359    Vfs(Vfs),
360    Peer(u32),
361    Icons(&'a [u8]),
362    Rqlen(Rqlen),
363    Meminfo(&'a [u8]),
364    Shutdown(u8),
365    Uid(u32),
366}
367impl<'a> IterableUnixDiagAttrs<'a> {
368    #[doc = "Unix socket sun\\_path\\. May or may not contain '\\\\0'\\."]
369    pub fn get_name(&self) -> Result<&'a [u8], ErrorContext> {
370        let mut iter = self.clone();
371        iter.pos = 0;
372        for attr in iter {
373            if let UnixDiagAttrs::Name(val) = attr? {
374                return Ok(val);
375            }
376        }
377        Err(ErrorContext::new_missing(
378            "UnixDiagAttrs",
379            "Name",
380            self.orig_loc,
381            self.buf.as_ptr() as usize,
382        ))
383    }
384    pub fn get_vfs(&self) -> Result<Vfs, ErrorContext> {
385        let mut iter = self.clone();
386        iter.pos = 0;
387        for attr in iter {
388            if let UnixDiagAttrs::Vfs(val) = attr? {
389                return Ok(val);
390            }
391        }
392        Err(ErrorContext::new_missing(
393            "UnixDiagAttrs",
394            "Vfs",
395            self.orig_loc,
396            self.buf.as_ptr() as usize,
397        ))
398    }
399    pub fn get_peer(&self) -> Result<u32, ErrorContext> {
400        let mut iter = self.clone();
401        iter.pos = 0;
402        for attr in iter {
403            if let UnixDiagAttrs::Peer(val) = attr? {
404                return Ok(val);
405            }
406        }
407        Err(ErrorContext::new_missing(
408            "UnixDiagAttrs",
409            "Peer",
410            self.orig_loc,
411            self.buf.as_ptr() as usize,
412        ))
413    }
414    pub fn get_icons(&self) -> Result<&'a [u8], ErrorContext> {
415        let mut iter = self.clone();
416        iter.pos = 0;
417        for attr in iter {
418            if let UnixDiagAttrs::Icons(val) = attr? {
419                return Ok(val);
420            }
421        }
422        Err(ErrorContext::new_missing(
423            "UnixDiagAttrs",
424            "Icons",
425            self.orig_loc,
426            self.buf.as_ptr() as usize,
427        ))
428    }
429    pub fn get_rqlen(&self) -> Result<Rqlen, ErrorContext> {
430        let mut iter = self.clone();
431        iter.pos = 0;
432        for attr in iter {
433            if let UnixDiagAttrs::Rqlen(val) = attr? {
434                return Ok(val);
435            }
436        }
437        Err(ErrorContext::new_missing(
438            "UnixDiagAttrs",
439            "Rqlen",
440            self.orig_loc,
441            self.buf.as_ptr() as usize,
442        ))
443    }
444    pub fn get_meminfo(&self) -> Result<&'a [u8], ErrorContext> {
445        let mut iter = self.clone();
446        iter.pos = 0;
447        for attr in iter {
448            if let UnixDiagAttrs::Meminfo(val) = attr? {
449                return Ok(val);
450            }
451        }
452        Err(ErrorContext::new_missing(
453            "UnixDiagAttrs",
454            "Meminfo",
455            self.orig_loc,
456            self.buf.as_ptr() as usize,
457        ))
458    }
459    pub fn get_shutdown(&self) -> Result<u8, ErrorContext> {
460        let mut iter = self.clone();
461        iter.pos = 0;
462        for attr in iter {
463            if let UnixDiagAttrs::Shutdown(val) = attr? {
464                return Ok(val);
465            }
466        }
467        Err(ErrorContext::new_missing(
468            "UnixDiagAttrs",
469            "Shutdown",
470            self.orig_loc,
471            self.buf.as_ptr() as usize,
472        ))
473    }
474    pub fn get_uid(&self) -> Result<u32, ErrorContext> {
475        let mut iter = self.clone();
476        iter.pos = 0;
477        for attr in iter {
478            if let UnixDiagAttrs::Uid(val) = attr? {
479                return Ok(val);
480            }
481        }
482        Err(ErrorContext::new_missing(
483            "UnixDiagAttrs",
484            "Uid",
485            self.orig_loc,
486            self.buf.as_ptr() as usize,
487        ))
488    }
489}
490impl UnixDiagAttrs<'_> {
491    pub fn new<'a>(buf: &'a [u8]) -> IterableUnixDiagAttrs<'a> {
492        IterableUnixDiagAttrs::with_loc(buf, buf.as_ptr() as usize)
493    }
494    fn attr_from_type(r#type: u16) -> Option<&'static str> {
495        let res = match r#type {
496            0u16 => "Name",
497            1u16 => "Vfs",
498            2u16 => "Peer",
499            3u16 => "Icons",
500            4u16 => "Rqlen",
501            5u16 => "Meminfo",
502            6u16 => "Shutdown",
503            7u16 => "Uid",
504            _ => return None,
505        };
506        Some(res)
507    }
508}
509#[derive(Clone, Copy, Default)]
510pub struct IterableUnixDiagAttrs<'a> {
511    buf: &'a [u8],
512    pos: usize,
513    orig_loc: usize,
514}
515impl<'a> IterableUnixDiagAttrs<'a> {
516    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
517        Self {
518            buf,
519            pos: 0,
520            orig_loc,
521        }
522    }
523    pub fn get_buf(&self) -> &'a [u8] {
524        self.buf
525    }
526}
527impl<'a> Iterator for IterableUnixDiagAttrs<'a> {
528    type Item = Result<UnixDiagAttrs<'a>, ErrorContext>;
529    fn next(&mut self) -> Option<Self::Item> {
530        let pos = self.pos;
531        let mut r#type;
532        loop {
533            r#type = None;
534            if self.buf.len() == self.pos {
535                return None;
536            }
537            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
538                break;
539            };
540            r#type = Some(header.r#type);
541            let res = match header.r#type {
542                0u16 => UnixDiagAttrs::Name({
543                    let res = Some(next);
544                    let Some(val) = res else { break };
545                    val
546                }),
547                1u16 => UnixDiagAttrs::Vfs({
548                    let res = Some(Vfs::new_from_zeroed(next));
549                    let Some(val) = res else { break };
550                    val
551                }),
552                2u16 => UnixDiagAttrs::Peer({
553                    let res = parse_u32(next);
554                    let Some(val) = res else { break };
555                    val
556                }),
557                3u16 => UnixDiagAttrs::Icons({
558                    let res = Some(next);
559                    let Some(val) = res else { break };
560                    val
561                }),
562                4u16 => UnixDiagAttrs::Rqlen({
563                    let res = Some(Rqlen::new_from_zeroed(next));
564                    let Some(val) = res else { break };
565                    val
566                }),
567                5u16 => UnixDiagAttrs::Meminfo({
568                    let res = Some(next);
569                    let Some(val) = res else { break };
570                    val
571                }),
572                6u16 => UnixDiagAttrs::Shutdown({
573                    let res = parse_u8(next);
574                    let Some(val) = res else { break };
575                    val
576                }),
577                7u16 => UnixDiagAttrs::Uid({
578                    let res = parse_u32(next);
579                    let Some(val) = res else { break };
580                    val
581                }),
582                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
583                n => continue,
584            };
585            return Some(Ok(res));
586        }
587        Some(Err(ErrorContext::new(
588            "UnixDiagAttrs",
589            r#type.and_then(|t| UnixDiagAttrs::attr_from_type(t)),
590            self.orig_loc,
591            self.buf.as_ptr().wrapping_add(pos) as usize,
592        )))
593    }
594}
595impl<'a> std::fmt::Debug for IterableUnixDiagAttrs<'_> {
596    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
597        let mut fmt = f.debug_struct("UnixDiagAttrs");
598        for attr in self.clone() {
599            let attr = match attr {
600                Ok(a) => a,
601                Err(err) => {
602                    fmt.finish()?;
603                    f.write_str("Err(")?;
604                    err.fmt(f)?;
605                    return f.write_str(")");
606                }
607            };
608            match attr {
609                UnixDiagAttrs::Name(val) => fmt.field("Name", &FormatBinStr(val)),
610                UnixDiagAttrs::Vfs(val) => fmt.field("Vfs", &val),
611                UnixDiagAttrs::Peer(val) => fmt.field("Peer", &val),
612                UnixDiagAttrs::Icons(val) => fmt.field("Icons", &val),
613                UnixDiagAttrs::Rqlen(val) => fmt.field("Rqlen", &val),
614                UnixDiagAttrs::Meminfo(val) => fmt.field("Meminfo", &val),
615                UnixDiagAttrs::Shutdown(val) => fmt.field("Shutdown", &val),
616                UnixDiagAttrs::Uid(val) => fmt.field("Uid", &val),
617            };
618        }
619        fmt.finish()
620    }
621}
622impl IterableUnixDiagAttrs<'_> {
623    pub fn lookup_attr(
624        &self,
625        offset: usize,
626        missing_type: Option<u16>,
627    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
628        let mut stack = Vec::new();
629        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
630        if missing_type.is_some() && cur == offset {
631            stack.push(("UnixDiagAttrs", offset));
632            return (
633                stack,
634                missing_type.and_then(|t| UnixDiagAttrs::attr_from_type(t)),
635            );
636        }
637        if cur > offset || cur + self.buf.len() < offset {
638            return (stack, None);
639        }
640        let mut attrs = self.clone();
641        let mut last_off = cur + attrs.pos;
642        while let Some(attr) = attrs.next() {
643            let Ok(attr) = attr else { break };
644            match attr {
645                UnixDiagAttrs::Name(val) => {
646                    if last_off == offset {
647                        stack.push(("Name", last_off));
648                        break;
649                    }
650                }
651                UnixDiagAttrs::Vfs(val) => {
652                    if last_off == offset {
653                        stack.push(("Vfs", last_off));
654                        break;
655                    }
656                }
657                UnixDiagAttrs::Peer(val) => {
658                    if last_off == offset {
659                        stack.push(("Peer", last_off));
660                        break;
661                    }
662                }
663                UnixDiagAttrs::Icons(val) => {
664                    if last_off == offset {
665                        stack.push(("Icons", last_off));
666                        break;
667                    }
668                }
669                UnixDiagAttrs::Rqlen(val) => {
670                    if last_off == offset {
671                        stack.push(("Rqlen", last_off));
672                        break;
673                    }
674                }
675                UnixDiagAttrs::Meminfo(val) => {
676                    if last_off == offset {
677                        stack.push(("Meminfo", last_off));
678                        break;
679                    }
680                }
681                UnixDiagAttrs::Shutdown(val) => {
682                    if last_off == offset {
683                        stack.push(("Shutdown", last_off));
684                        break;
685                    }
686                }
687                UnixDiagAttrs::Uid(val) => {
688                    if last_off == offset {
689                        stack.push(("Uid", last_off));
690                        break;
691                    }
692                }
693                _ => {}
694            };
695            last_off = cur + attrs.pos;
696        }
697        if !stack.is_empty() {
698            stack.push(("UnixDiagAttrs", cur));
699        }
700        (stack, None)
701    }
702}
703pub struct PushUnixDiagAttrs<Prev: Rec> {
704    pub(crate) prev: Option<Prev>,
705    pub(crate) header_offset: Option<usize>,
706}
707impl<Prev: Rec> Rec for PushUnixDiagAttrs<Prev> {
708    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
709        self.prev.as_mut().unwrap().as_rec_mut()
710    }
711    fn as_rec(&self) -> &Vec<u8> {
712        self.prev.as_ref().unwrap().as_rec()
713    }
714}
715impl<Prev: Rec> PushUnixDiagAttrs<Prev> {
716    pub fn new(prev: Prev) -> Self {
717        Self {
718            prev: Some(prev),
719            header_offset: None,
720        }
721    }
722    pub fn end_nested(mut self) -> Prev {
723        let mut prev = self.prev.take().unwrap();
724        if let Some(header_offset) = &self.header_offset {
725            finalize_nested_header(prev.as_rec_mut(), *header_offset);
726        }
727        prev
728    }
729    #[doc = "Unix socket sun\\_path\\. May or may not contain '\\\\0'\\."]
730    pub fn push_name(mut self, value: &[u8]) -> Self {
731        push_header(self.as_rec_mut(), 0u16, value.len() as u16);
732        self.as_rec_mut().extend(value);
733        self
734    }
735    pub fn push_vfs(mut self, value: Vfs) -> Self {
736        push_header(self.as_rec_mut(), 1u16, value.as_slice().len() as u16);
737        self.as_rec_mut().extend(value.as_slice());
738        self
739    }
740    pub fn push_peer(mut self, value: u32) -> Self {
741        push_header(self.as_rec_mut(), 2u16, 4 as u16);
742        self.as_rec_mut().extend(value.to_ne_bytes());
743        self
744    }
745    pub fn push_icons(mut self, value: &[u8]) -> Self {
746        push_header(self.as_rec_mut(), 3u16, value.len() as u16);
747        self.as_rec_mut().extend(value);
748        self
749    }
750    pub fn push_rqlen(mut self, value: Rqlen) -> Self {
751        push_header(self.as_rec_mut(), 4u16, value.as_slice().len() as u16);
752        self.as_rec_mut().extend(value.as_slice());
753        self
754    }
755    pub fn push_meminfo(mut self, value: &[u8]) -> Self {
756        push_header(self.as_rec_mut(), 5u16, value.len() as u16);
757        self.as_rec_mut().extend(value);
758        self
759    }
760    pub fn push_shutdown(mut self, value: u8) -> Self {
761        push_header(self.as_rec_mut(), 6u16, 1 as u16);
762        self.as_rec_mut().extend(value.to_ne_bytes());
763        self
764    }
765    pub fn push_uid(mut self, value: u32) -> Self {
766        push_header(self.as_rec_mut(), 7u16, 4 as u16);
767        self.as_rec_mut().extend(value.to_ne_bytes());
768        self
769    }
770}
771impl<Prev: Rec> Drop for PushUnixDiagAttrs<Prev> {
772    fn drop(&mut self) {
773        if let Some(prev) = &mut self.prev {
774            if let Some(header_offset) = &self.header_offset {
775                finalize_nested_header(prev.as_rec_mut(), *header_offset);
776            }
777        }
778    }
779}
780#[doc = ""]
781#[derive(Debug)]
782pub struct OpUnixDiagDump<'r> {
783    request: Request<'r>,
784}
785impl<'r> OpUnixDiagDump<'r> {
786    pub fn new(mut request: Request<'r>, header: &Req) -> Self {
787        Self::write_header(request.buf_mut(), header);
788        Self {
789            request: request.set_dump(),
790        }
791    }
792    pub fn encode_request<'buf>(
793        buf: &'buf mut Vec<u8>,
794        header: &Req,
795    ) -> PushUnixDiagAttrs<&'buf mut Vec<u8>> {
796        Self::write_header(buf, header);
797        PushUnixDiagAttrs::new(buf)
798    }
799    pub fn encode(&mut self) -> PushUnixDiagAttrs<&mut Vec<u8>> {
800        PushUnixDiagAttrs::new(self.request.buf_mut())
801    }
802    pub fn into_encoder(self) -> PushUnixDiagAttrs<RequestBuf<'r>> {
803        PushUnixDiagAttrs::new(self.request.buf)
804    }
805    pub fn decode_request<'a>(buf: &'a [u8]) -> (Req, IterableUnixDiagAttrs<'a>) {
806        let (header, attrs) = buf.split_at(buf.len().min(Req::len()));
807        (
808            Req::new_from_slice(header).unwrap_or_default(),
809            IterableUnixDiagAttrs::with_loc(attrs, buf.as_ptr() as usize),
810        )
811    }
812    fn decode_reply<'a>(buf: &'a [u8]) -> (Msg, IterableUnixDiagAttrs<'a>) {
813        let (header, attrs) = buf.split_at(buf.len().min(Msg::len()));
814        (
815            Msg::new_from_slice(header).unwrap_or_default(),
816            IterableUnixDiagAttrs::with_loc(attrs, buf.as_ptr() as usize),
817        )
818    }
819    fn write_header<Prev: Rec>(prev: &mut Prev, header: &Req) {
820        prev.as_rec_mut().extend(header.as_slice());
821    }
822}
823impl NetlinkRequest for OpUnixDiagDump<'_> {
824    fn protocol(&self) -> Protocol {
825        Protocol::Raw {
826            protonum: 4u16,
827            request_type: 20u16,
828        }
829    }
830    fn flags(&self) -> u16 {
831        self.request.flags
832    }
833    fn payload(&self) -> &[u8] {
834        self.request.buf()
835    }
836    type ReplyType<'buf> = (Msg, IterableUnixDiagAttrs<'buf>);
837    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
838        Self::decode_reply(buf)
839    }
840    fn lookup(
841        buf: &[u8],
842        offset: usize,
843        missing_type: Option<u16>,
844    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
845        Self::decode_request(buf)
846            .1
847            .lookup_attr(offset, missing_type)
848    }
849}
850#[derive(Debug)]
851pub struct ChainedFinal<'a> {
852    inner: Chained<'a>,
853}
854#[derive(Debug)]
855pub struct Chained<'a> {
856    buf: RequestBuf<'a>,
857    first_seq: u32,
858    lookups: Vec<(&'static str, LookupFn)>,
859    last_header_offset: usize,
860    last_kind: Option<RequestInfo>,
861}
862impl<'a> ChainedFinal<'a> {
863    pub fn into_chained(self) -> Chained<'a> {
864        self.inner
865    }
866    pub fn buf(&self) -> &Vec<u8> {
867        self.inner.buf()
868    }
869    pub fn buf_mut(&mut self) -> &mut Vec<u8> {
870        self.inner.buf_mut()
871    }
872    fn get_index(&self, seq: u32) -> Option<u32> {
873        let min = self.inner.first_seq;
874        let max = min.wrapping_add(self.inner.lookups.len() as u32);
875        return if min <= max {
876            (min..max).contains(&seq).then(|| seq - min)
877        } else if min <= seq {
878            Some(seq - min)
879        } else if seq < max {
880            Some(u32::MAX - min + seq)
881        } else {
882            None
883        };
884    }
885}
886impl crate::traits::NetlinkChained for ChainedFinal<'_> {
887    fn protonum(&self) -> u16 {
888        PROTONUM
889    }
890    fn payload(&self) -> &[u8] {
891        self.buf()
892    }
893    fn chain_len(&self) -> usize {
894        self.inner.lookups.len()
895    }
896    fn get_index(&self, seq: u32) -> Option<usize> {
897        self.get_index(seq).map(|n| n as usize)
898    }
899    fn name(&self, index: usize) -> &'static str {
900        self.inner.lookups[index].0
901    }
902    fn lookup(&self, index: usize) -> LookupFn {
903        self.inner.lookups[index].1
904    }
905}
906impl Chained<'static> {
907    pub fn new(first_seq: u32) -> Self {
908        Self::new_from_buf(Vec::new(), first_seq)
909    }
910    pub fn new_from_buf(buf: Vec<u8>, first_seq: u32) -> Self {
911        Self {
912            buf: RequestBuf::Own(buf),
913            first_seq,
914            lookups: Vec::new(),
915            last_header_offset: 0,
916            last_kind: None,
917        }
918    }
919    pub fn into_buf(self) -> Vec<u8> {
920        match self.buf {
921            RequestBuf::Own(buf) => buf,
922            _ => unreachable!(),
923        }
924    }
925}
926impl<'a> Chained<'a> {
927    pub fn new_with_buf(buf: &'a mut Vec<u8>, first_seq: u32) -> Self {
928        Self {
929            buf: RequestBuf::Ref(buf),
930            first_seq,
931            lookups: Vec::new(),
932            last_header_offset: 0,
933            last_kind: None,
934        }
935    }
936    pub fn finalize(mut self) -> ChainedFinal<'a> {
937        self.update_header();
938        ChainedFinal { inner: self }
939    }
940    pub fn request(&mut self) -> Request<'_> {
941        self.update_header();
942        self.last_header_offset = self.buf().len();
943        self.buf_mut().extend_from_slice(Nlmsghdr::new().as_slice());
944        let mut request = Request::new_extend(self.buf.buf_mut());
945        self.last_kind = None;
946        request.writeback = Some(&mut self.last_kind);
947        request
948    }
949    pub fn buf(&self) -> &Vec<u8> {
950        self.buf.buf()
951    }
952    pub fn buf_mut(&mut self) -> &mut Vec<u8> {
953        self.buf.buf_mut()
954    }
955    fn update_header(&mut self) {
956        let Some(RequestInfo {
957            protocol,
958            flags,
959            name,
960            lookup,
961        }) = self.last_kind
962        else {
963            if !self.buf().is_empty() {
964                assert_eq!(self.last_header_offset + Nlmsghdr::len(), self.buf().len());
965                self.buf.buf_mut().truncate(self.last_header_offset);
966            }
967            return;
968        };
969        let header_offset = self.last_header_offset;
970        let request_type = match protocol {
971            Protocol::Raw { request_type, .. } => request_type,
972            Protocol::Generic(_) => unreachable!(),
973        };
974        let index = self.lookups.len();
975        let seq = self.first_seq.wrapping_add(index as u32);
976        self.lookups.push((name, lookup));
977        let buf = self.buf_mut();
978        align(buf);
979        let header = Nlmsghdr {
980            len: (buf.len() - header_offset) as u32,
981            r#type: request_type,
982            flags: flags | consts::NLM_F_REQUEST as u16 | consts::NLM_F_ACK as u16,
983            seq,
984            pid: 0,
985        };
986        buf[header_offset..(header_offset + 16)].clone_from_slice(header.as_slice());
987    }
988}
989use crate::traits::LookupFn;
990use crate::utils::RequestBuf;
991#[derive(Debug)]
992pub struct Request<'buf> {
993    buf: RequestBuf<'buf>,
994    flags: u16,
995    writeback: Option<&'buf mut Option<RequestInfo>>,
996}
997#[allow(unused)]
998#[derive(Debug, Clone)]
999pub struct RequestInfo {
1000    protocol: Protocol,
1001    flags: u16,
1002    name: &'static str,
1003    lookup: LookupFn,
1004}
1005impl Request<'static> {
1006    pub fn new() -> Self {
1007        Self::new_from_buf(Vec::new())
1008    }
1009    pub fn new_from_buf(buf: Vec<u8>) -> Self {
1010        Self {
1011            flags: 0,
1012            buf: RequestBuf::Own(buf),
1013            writeback: None,
1014        }
1015    }
1016    pub fn into_buf(self) -> Vec<u8> {
1017        match self.buf {
1018            RequestBuf::Own(buf) => buf,
1019            _ => unreachable!(),
1020        }
1021    }
1022}
1023impl<'buf> Request<'buf> {
1024    pub fn new_with_buf(buf: &'buf mut Vec<u8>) -> Self {
1025        buf.clear();
1026        Self::new_extend(buf)
1027    }
1028    pub fn new_extend(buf: &'buf mut Vec<u8>) -> Self {
1029        Self {
1030            flags: 0,
1031            buf: RequestBuf::Ref(buf),
1032            writeback: None,
1033        }
1034    }
1035    fn do_writeback(&mut self, protocol: Protocol, name: &'static str, lookup: LookupFn) {
1036        let Some(writeback) = &mut self.writeback else {
1037            return;
1038        };
1039        **writeback = Some(RequestInfo {
1040            protocol,
1041            flags: self.flags,
1042            name,
1043            lookup,
1044        })
1045    }
1046    pub fn buf(&self) -> &Vec<u8> {
1047        self.buf.buf()
1048    }
1049    pub fn buf_mut(&mut self) -> &mut Vec<u8> {
1050        self.buf.buf_mut()
1051    }
1052    #[doc = "Set `NLM_F_CREATE` flag"]
1053    pub fn set_create(mut self) -> Self {
1054        self.flags |= consts::NLM_F_CREATE as u16;
1055        self
1056    }
1057    #[doc = "Set `NLM_F_EXCL` flag"]
1058    pub fn set_excl(mut self) -> Self {
1059        self.flags |= consts::NLM_F_EXCL as u16;
1060        self
1061    }
1062    #[doc = "Set `NLM_F_REPLACE` flag"]
1063    pub fn set_replace(mut self) -> Self {
1064        self.flags |= consts::NLM_F_REPLACE as u16;
1065        self
1066    }
1067    #[doc = "Set `NLM_F_CREATE` and `NLM_F_REPLACE` flag"]
1068    pub fn set_change(self) -> Self {
1069        self.set_create().set_replace()
1070    }
1071    #[doc = "Set `NLM_F_APPEND` flag"]
1072    pub fn set_append(mut self) -> Self {
1073        self.flags |= consts::NLM_F_APPEND as u16;
1074        self
1075    }
1076    #[doc = "Set `self.flags |= flags`"]
1077    pub fn set_flags(mut self, flags: u16) -> Self {
1078        self.flags |= flags;
1079        self
1080    }
1081    #[doc = "Set `self.flags ^= self.flags & flags`"]
1082    pub fn unset_flags(mut self, flags: u16) -> Self {
1083        self.flags ^= self.flags & flags;
1084        self
1085    }
1086    #[doc = "Set `NLM_F_DUMP` flag"]
1087    fn set_dump(mut self) -> Self {
1088        self.flags |= consts::NLM_F_DUMP as u16;
1089        self
1090    }
1091    #[doc = ""]
1092    pub fn op_unix_diag_dump(self, header: &Req) -> OpUnixDiagDump<'buf> {
1093        let mut res = OpUnixDiagDump::new(self, header);
1094        res.request
1095            .do_writeback(res.protocol(), "op-unix-diag-dump", OpUnixDiagDump::lookup);
1096        res
1097    }
1098}