Skip to main content

shadow_rs/host/descriptor/socket/
netlink.rs

1use std::io::{Cursor, ErrorKind, Read, Write};
2use std::net::Ipv4Addr;
3use std::sync::{Arc, Weak};
4
5use atomic_refcell::AtomicRefCell;
6use linux_api::errno::Errno;
7use linux_api::ioctls::IoctlRequest;
8use linux_api::netlink::{ifaddrmsg, ifinfomsg, nlmsghdr};
9use linux_api::rtnetlink::{RTM_GETADDR, RTM_GETLINK, RTMGRP_IPV4_IFADDR, RTMGRP_IPV6_IFADDR};
10use linux_api::socket::Shutdown;
11use neli::consts::nl::{NlmF, Nlmsg};
12use neli::consts::rtnl::{Arphrd, Ifa, IfaF, Iff, Ifla, RtAddrFamily, RtScope, Rtm};
13use neli::nl::{NlPayload, Nlmsghdr, NlmsghdrBuilder};
14use neli::rtnl::{Ifaddrmsg, IfaddrmsgBuilder, Ifinfomsg, IfinfomsgBuilder, RtattrBuilder};
15use neli::types::{Buffer, RtBuffer};
16use neli::{FromBytes, ToBytes};
17use nix::sys::socket::{MsgFlags, NetlinkAddr};
18use shadow_shim_helper_rs::syscall_types::ForeignPtr;
19
20use crate::core::worker::Worker;
21use crate::cshadow as c;
22use crate::host::descriptor::listener::{StateEventSource, StateListenHandle, StateListenerFilter};
23use crate::host::descriptor::shared_buf::{
24    BufferHandle, BufferSignals, BufferState, ReaderHandle, SharedBuf,
25};
26use crate::host::descriptor::socket::{RecvmsgArgs, RecvmsgReturn, SendmsgArgs, Socket};
27use crate::host::descriptor::{
28    File, FileMode, FileSignals, FileState, FileStatus, OpenFile, SyscallResult,
29};
30use crate::host::memory_manager::MemoryManager;
31use crate::host::network::namespace::NetworkNamespace;
32use crate::host::syscall::io::{IoVec, IoVecReader, IoVecWriter};
33use crate::host::syscall::types::SyscallError;
34use crate::utility::HostTreePointer;
35use crate::utility::callback_queue::CallbackQueue;
36use crate::utility::sockaddr::SockaddrStorage;
37
38// this constant is copied from UNIX_SOCKET_DEFAULT_BUFFER_SIZE
39const NETLINK_SOCKET_DEFAULT_BUFFER_SIZE: u64 = 212_992;
40
41pub struct NetlinkSocket {
42    /// Data and functionality that is general for all states.
43    common: NetlinkSocketCommon,
44    /// State-specific data and functionality.
45    protocol_state: ProtocolState,
46}
47
48impl NetlinkSocket {
49    pub fn new(
50        status: FileStatus,
51        _socket_type: NetlinkSocketType,
52        _family: NetlinkFamily,
53    ) -> Arc<AtomicRefCell<Self>> {
54        Arc::new_cyclic(|weak| {
55            // each socket tracks its own send limit
56            let buffer = SharedBuf::new(usize::MAX);
57            let buffer = Arc::new(AtomicRefCell::new(buffer));
58
59            // Get the IP address of the host
60            let default_ip = Worker::with_active_host(|host| host.default_ip()).unwrap();
61            // All the interface configurations are the same as in the getifaddrs function handler
62            let interfaces = vec![
63                Interface {
64                    address: Ipv4Addr::LOCALHOST,
65                    label: String::from("lo"),
66                    prefix_len: 8,
67                    if_type: Arphrd::Loopback,
68                    mtu: c::CONFIG_MTU,
69                    scope: RtScope::Host,
70                    index: 1,
71                },
72                Interface {
73                    address: default_ip,
74                    label: String::from("eth0"),
75                    prefix_len: 24,
76                    if_type: Arphrd::Ether,
77                    mtu: c::CONFIG_MTU,
78                    scope: RtScope::Universe,
79                    index: 2,
80                },
81            ];
82
83            let mut common = NetlinkSocketCommon {
84                buffer,
85                send_limit: NETLINK_SOCKET_DEFAULT_BUFFER_SIZE,
86                sent_len: 0,
87                event_source: StateEventSource::new(),
88                state: FileState::ACTIVE,
89                status,
90                has_open_file: false,
91                interfaces,
92            };
93            let protocol_state = ProtocolState::new(&mut common, weak);
94            let mut socket = Self {
95                common,
96                protocol_state,
97            };
98            CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
99                socket.refresh_file_state(FileSignals::empty(), cb_queue)
100            });
101
102            AtomicRefCell::new(socket)
103        })
104    }
105
106    pub fn status(&self) -> FileStatus {
107        self.common.status
108    }
109
110    pub fn set_status(&mut self, status: FileStatus) {
111        self.common.status = status;
112    }
113
114    pub fn mode(&self) -> FileMode {
115        FileMode::READ | FileMode::WRITE
116    }
117
118    pub fn has_open_file(&self) -> bool {
119        self.common.has_open_file
120    }
121
122    pub fn supports_sa_restart(&self) -> bool {
123        self.common.supports_sa_restart()
124    }
125
126    pub fn set_has_open_file(&mut self, val: bool) {
127        self.common.has_open_file = val;
128    }
129
130    pub fn getsockname(&self) -> Result<Option<nix::sys::socket::NetlinkAddr>, Errno> {
131        self.protocol_state.bound_address()
132    }
133
134    pub fn getpeername(&self) -> Result<Option<nix::sys::socket::NetlinkAddr>, Errno> {
135        warn_once_then_debug!(
136            "getpeername() syscall not yet supported for netlink sockets; Returning ENOSYS"
137        );
138        Err(Errno::ENOSYS)
139    }
140
141    pub fn address_family(&self) -> linux_api::socket::AddressFamily {
142        linux_api::socket::AddressFamily::AF_NETLINK
143    }
144
145    pub fn close(&mut self, cb_queue: &mut CallbackQueue) -> Result<(), SyscallError> {
146        self.protocol_state.close(&mut self.common, cb_queue)
147    }
148
149    fn refresh_file_state(&mut self, signals: FileSignals, cb_queue: &mut CallbackQueue) {
150        self.protocol_state
151            .refresh_file_state(&mut self.common, signals, cb_queue)
152    }
153
154    pub fn shutdown(
155        &mut self,
156        _how: Shutdown,
157        _cb_queue: &mut CallbackQueue,
158    ) -> Result<(), SyscallError> {
159        warn_once_then_debug!(
160            "shutdown() syscall not yet supported for netlink sockets; Returning ENOSYS"
161        );
162        Err(Errno::ENOSYS.into())
163    }
164
165    pub fn getsockopt(
166        &mut self,
167        _level: libc::c_int,
168        _optname: libc::c_int,
169        _optval_ptr: ForeignPtr<()>,
170        _optlen: libc::socklen_t,
171        _memory_manager: &mut MemoryManager,
172        _cb_queue: &mut CallbackQueue,
173    ) -> Result<libc::socklen_t, SyscallError> {
174        warn_once_then_debug!(
175            "getsockopt() syscall not yet supported for netlink sockets; Returning ENOSYS"
176        );
177        Err(Errno::ENOSYS.into())
178    }
179
180    pub fn setsockopt(
181        &mut self,
182        level: libc::c_int,
183        optname: libc::c_int,
184        optval_ptr: ForeignPtr<()>,
185        optlen: libc::socklen_t,
186        memory_manager: &MemoryManager,
187    ) -> Result<(), SyscallError> {
188        match (level, optname) {
189            (libc::SOL_SOCKET, libc::SO_SNDBUF) => {
190                type OptType = libc::c_int;
191
192                if usize::try_from(optlen).unwrap() < std::mem::size_of::<OptType>() {
193                    return Err(Errno::EINVAL.into());
194                }
195
196                let optval_ptr = optval_ptr.cast::<OptType>();
197                let val: u64 = memory_manager
198                    .read(optval_ptr)?
199                    .try_into()
200                    .or(Err(Errno::EINVAL))?;
201
202                // Linux kernel doubles this value upon setting
203                let val = val * 2;
204                // We want to keep sent_len lower than send_limit
205                let val = std::cmp::max(val, self.common.sent_len);
206                // Copied the following behaviour from setsockopt of LegacyTcpSocket
207                let val = std::cmp::max(val, 4096);
208                let val = std::cmp::min(val, 268435456); // 2^28 = 256 MiB
209
210                self.common.send_limit = val;
211            }
212            (libc::SOL_SOCKET, libc::SO_RCVBUF) => {
213                // We don't care about the receive buffer size because we already limit the send
214                // buffer size and when recvmsg is called we just retrieve the request packet from
215                // the send buffer, process it, and return the response immediately to the caller
216            }
217            _ => {
218                warn_once_then_debug!(
219                    "setsockopt called with unsupported level {level} and opt {optname}"
220                );
221                return Err(Errno::ENOPROTOOPT.into());
222            }
223        }
224
225        Ok(())
226    }
227
228    pub fn bind(
229        socket: &Arc<AtomicRefCell<Self>>,
230        addr: Option<&SockaddrStorage>,
231        _net_ns: &NetworkNamespace,
232        rng: impl rand::Rng,
233    ) -> Result<(), SyscallError> {
234        let socket_ref = &mut *socket.borrow_mut();
235        socket_ref
236            .protocol_state
237            .bind(&mut socket_ref.common, socket, addr, rng)
238    }
239
240    pub fn readv(
241        &mut self,
242        _iovs: &[IoVec],
243        _offset: Option<libc::off_t>,
244        _flags: libc::c_int,
245        _mem: &mut MemoryManager,
246        _cb_queue: &mut CallbackQueue,
247    ) -> Result<libc::ssize_t, SyscallError> {
248        // we could call NetlinkSocket::recvmsg() here, but for now we expect that there are no code
249        // paths that would call NetlinkSocket::readv() since the readv() syscall handler should have
250        // called NetlinkSocket::recvmsg() instead
251        panic!("Called NetlinkSocket::readv() on a netlink socket.");
252    }
253
254    pub fn writev(
255        &mut self,
256        _iovs: &[IoVec],
257        _offset: Option<libc::off_t>,
258        _flags: libc::c_int,
259        _mem: &mut MemoryManager,
260        _cb_queue: &mut CallbackQueue,
261    ) -> Result<libc::ssize_t, SyscallError> {
262        // we could call NetlinkSocket::sendmsg() here, but for now we expect that there are no code
263        // paths that would call NetlinkSocket::writev() since the writev() syscall handler should have
264        // called NetlinkSocket::sendmsg() instead
265        panic!("Called NetlinkSocket::writev() on a netlink socket");
266    }
267
268    pub fn sendmsg(
269        socket: &Arc<AtomicRefCell<Self>>,
270        args: SendmsgArgs,
271        mem: &mut MemoryManager,
272        _net_ns: &NetworkNamespace,
273        _rng: impl rand::Rng,
274        cb_queue: &mut CallbackQueue,
275    ) -> Result<libc::ssize_t, SyscallError> {
276        let socket_ref = &mut *socket.borrow_mut();
277        socket_ref
278            .protocol_state
279            .sendmsg(&mut socket_ref.common, socket, args, mem, cb_queue)
280    }
281
282    pub fn recvmsg(
283        socket: &Arc<AtomicRefCell<Self>>,
284        args: RecvmsgArgs,
285        mem: &mut MemoryManager,
286        cb_queue: &mut CallbackQueue,
287    ) -> Result<RecvmsgReturn, SyscallError> {
288        let socket_ref = &mut *socket.borrow_mut();
289        socket_ref
290            .protocol_state
291            .recvmsg(&mut socket_ref.common, socket, args, mem, cb_queue)
292    }
293
294    pub fn listen(
295        _socket: &Arc<AtomicRefCell<Self>>,
296        _backlog: i32,
297        _net_ns: &NetworkNamespace,
298        _rng: impl rand::Rng,
299        _cb_queue: &mut CallbackQueue,
300    ) -> Result<(), Errno> {
301        warn_once_then_debug!("We do not yet handle listen request on netlink sockets");
302        Err(Errno::EINVAL)
303    }
304
305    pub fn connect(
306        _socket: &Arc<AtomicRefCell<Self>>,
307        _addr: &SockaddrStorage,
308        _net_ns: &NetworkNamespace,
309        _rng: impl rand::Rng,
310        _cb_queue: &mut CallbackQueue,
311    ) -> Result<(), SyscallError> {
312        warn_once_then_debug!("We do not yet handle connect request on netlink sockets");
313        Err(Errno::EINVAL.into())
314    }
315
316    pub fn accept(
317        &mut self,
318        _net_ns: &NetworkNamespace,
319        _rng: impl rand::Rng,
320        _cb_queue: &mut CallbackQueue,
321    ) -> Result<OpenFile, SyscallError> {
322        warn_once_then_debug!("We do not yet handle accept request on netlink sockets");
323        Err(Errno::EINVAL.into())
324    }
325
326    pub fn ioctl(
327        &mut self,
328        request: IoctlRequest,
329        _arg_ptr: ForeignPtr<()>,
330        _memory_manager: &mut MemoryManager,
331    ) -> SyscallResult {
332        warn_once_then_debug!("We do not yet handle ioctl request {request:?} on netlink sockets");
333        Err(Errno::EINVAL.into())
334    }
335
336    pub fn stat(&self) -> Result<linux_api::stat::stat, SyscallError> {
337        warn_once_then_debug!("We do not yet handle stat calls on netlink sockets");
338        Err(Errno::EINVAL.into())
339    }
340
341    pub fn lseek(
342        &mut self,
343        _off: linux_api::posix_types::kernel_off_t,
344        _whence: linux_api::unistd::LSeekWhence,
345    ) -> Result<linux_api::posix_types::kernel_off_t, SyscallError> {
346        warn_once_then_debug!("We do not yet handle lseek calls on netlink sockets");
347        Err(Errno::EBADF.into())
348    }
349
350    pub fn add_listener(
351        &mut self,
352        monitoring_state: FileState,
353        monitoring_signals: FileSignals,
354        filter: StateListenerFilter,
355        notify_fn: impl Fn(FileState, FileState, FileSignals, &mut CallbackQueue)
356        + Send
357        + Sync
358        + 'static,
359    ) -> StateListenHandle {
360        self.common.event_source.add_listener(
361            monitoring_state,
362            monitoring_signals,
363            filter,
364            notify_fn,
365        )
366    }
367
368    pub fn add_legacy_listener(&mut self, ptr: HostTreePointer<c::StatusListener>) {
369        self.common.event_source.add_legacy_listener(ptr);
370    }
371
372    pub fn remove_legacy_listener(&mut self, ptr: *mut c::StatusListener) {
373        self.common.event_source.remove_legacy_listener(ptr);
374    }
375
376    pub fn state(&self) -> FileState {
377        self.common.state
378    }
379}
380
381struct InitialState {
382    bound_addr: Option<NetlinkAddr>,
383    reader_handle: ReaderHandle,
384    // this handle is never accessed, but we store it because of its drop impl
385    _buffer_handle: BufferHandle,
386}
387struct ClosedState {}
388/// The current protocol state of the netlink socket. An `Option` is required for each variant so that
389/// the inner state object can be removed, transformed into a new state, and then re-added as a
390/// different variant.
391enum ProtocolState {
392    Initial(Option<InitialState>),
393    Closed(Option<ClosedState>),
394}
395
396/// Upcast from a type to an enum variant.
397macro_rules! state_upcast {
398    ($type:ty, $parent:ident::$variant:ident) => {
399        impl From<$type> for $parent {
400            fn from(x: $type) -> Self {
401                Self::$variant(Some(x))
402            }
403        }
404    };
405}
406
407// implement upcasting for all state types
408state_upcast!(InitialState, ProtocolState::Initial);
409state_upcast!(ClosedState, ProtocolState::Closed);
410
411impl ProtocolState {
412    fn new(common: &mut NetlinkSocketCommon, socket: &Weak<AtomicRefCell<NetlinkSocket>>) -> Self {
413        // this is a new socket and there are no listeners, so safe to use a temporary event queue
414        let mut cb_queue = CallbackQueue::new();
415
416        // increment the buffer's reader count
417        let reader_handle = common.buffer.borrow_mut().add_reader(&mut cb_queue);
418
419        let weak = Weak::clone(socket);
420        let buffer_handle = common.buffer.borrow_mut().add_listener(
421            BufferState::READABLE,
422            BufferSignals::BUFFER_GREW,
423            move |_, signals, cb_queue| {
424                if let Some(socket) = weak.upgrade() {
425                    let signals = if signals.contains(BufferSignals::BUFFER_GREW) {
426                        FileSignals::READ_BUFFER_GREW
427                    } else {
428                        FileSignals::empty()
429                    };
430
431                    socket.borrow_mut().refresh_file_state(signals, cb_queue);
432                }
433            },
434        );
435
436        ProtocolState::Initial(Some(InitialState {
437            bound_addr: None,
438            reader_handle,
439            _buffer_handle: buffer_handle,
440        }))
441    }
442
443    fn bound_address(&self) -> Result<Option<NetlinkAddr>, Errno> {
444        match self {
445            Self::Initial(x) => x.as_ref().unwrap().bound_address(),
446            Self::Closed(x) => x.as_ref().unwrap().bound_address(),
447        }
448    }
449
450    fn refresh_file_state(
451        &self,
452        common: &mut NetlinkSocketCommon,
453        signals: FileSignals,
454        cb_queue: &mut CallbackQueue,
455    ) {
456        match self {
457            Self::Initial(x) => x
458                .as_ref()
459                .unwrap()
460                .refresh_file_state(common, signals, cb_queue),
461            Self::Closed(x) => x
462                .as_ref()
463                .unwrap()
464                .refresh_file_state(common, signals, cb_queue),
465        }
466    }
467
468    fn close(
469        &mut self,
470        common: &mut NetlinkSocketCommon,
471        cb_queue: &mut CallbackQueue,
472    ) -> Result<(), SyscallError> {
473        let (new_state, rv) = match self {
474            Self::Initial(x) => x.take().unwrap().close(common, cb_queue),
475            Self::Closed(x) => x.take().unwrap().close(common, cb_queue),
476        };
477
478        *self = new_state;
479        rv
480    }
481
482    fn bind(
483        &mut self,
484        common: &mut NetlinkSocketCommon,
485        socket: &Arc<AtomicRefCell<NetlinkSocket>>,
486        addr: Option<&SockaddrStorage>,
487        rng: impl rand::Rng,
488    ) -> Result<(), SyscallError> {
489        match self {
490            Self::Initial(x) => x.as_mut().unwrap().bind(common, socket, addr, rng),
491            Self::Closed(x) => x.as_mut().unwrap().bind(common, socket, addr, rng),
492        }
493    }
494
495    fn sendmsg(
496        &mut self,
497        common: &mut NetlinkSocketCommon,
498        socket: &Arc<AtomicRefCell<NetlinkSocket>>,
499        args: SendmsgArgs,
500        mem: &mut MemoryManager,
501        cb_queue: &mut CallbackQueue,
502    ) -> Result<libc::ssize_t, SyscallError> {
503        match self {
504            Self::Initial(x) => x
505                .as_mut()
506                .unwrap()
507                .sendmsg(common, socket, args, mem, cb_queue),
508            Self::Closed(x) => x
509                .as_mut()
510                .unwrap()
511                .sendmsg(common, socket, args, mem, cb_queue),
512        }
513    }
514
515    fn recvmsg(
516        &mut self,
517        common: &mut NetlinkSocketCommon,
518        socket: &Arc<AtomicRefCell<NetlinkSocket>>,
519        args: RecvmsgArgs,
520        mem: &mut MemoryManager,
521        cb_queue: &mut CallbackQueue,
522    ) -> Result<RecvmsgReturn, SyscallError> {
523        match self {
524            Self::Initial(x) => x
525                .as_mut()
526                .unwrap()
527                .recvmsg(common, socket, args, mem, cb_queue),
528            Self::Closed(x) => x
529                .as_mut()
530                .unwrap()
531                .recvmsg(common, socket, args, mem, cb_queue),
532        }
533    }
534}
535
536impl InitialState {
537    fn bound_address(&self) -> Result<Option<NetlinkAddr>, Errno> {
538        Ok(self.bound_addr)
539    }
540
541    fn refresh_file_state(
542        &self,
543        common: &mut NetlinkSocketCommon,
544        signals: FileSignals,
545        cb_queue: &mut CallbackQueue,
546    ) {
547        let mut new_state = FileState::ACTIVE;
548
549        {
550            let buffer = common.buffer.borrow();
551
552            new_state.set(FileState::READABLE, buffer.has_data());
553            new_state.set(FileState::WRITABLE, common.sent_len < common.send_limit);
554        }
555
556        common.update_state(
557            /* mask= */ FileState::all(),
558            new_state,
559            signals,
560            cb_queue,
561        );
562    }
563
564    fn close(
565        self,
566        common: &mut NetlinkSocketCommon,
567        cb_queue: &mut CallbackQueue,
568    ) -> (ProtocolState, Result<(), SyscallError>) {
569        // inform the buffer that there is one fewer readers
570        common
571            .buffer
572            .borrow_mut()
573            .remove_reader(self.reader_handle, cb_queue);
574
575        let new_state = ClosedState {};
576        new_state.refresh_file_state(common, FileSignals::empty(), cb_queue);
577        (new_state.into(), Ok(()))
578    }
579
580    fn bind(
581        &mut self,
582        _common: &mut NetlinkSocketCommon,
583        _socket: &Arc<AtomicRefCell<NetlinkSocket>>,
584        addr: Option<&SockaddrStorage>,
585        _rng: impl rand::Rng,
586    ) -> Result<(), SyscallError> {
587        // if already bound
588        if self.bound_addr.is_some() {
589            return Err(Errno::EINVAL.into());
590        }
591        // if the bound address is null
592        if addr.is_none() {
593            return Err(Errno::EFAULT.into());
594        }
595
596        // get the netlink address
597        let Some(addr) = addr.and_then(|x| x.as_netlink()) else {
598            log::warn!("Attempted to bind netlink socket to non-netlink address {addr:?}");
599            return Err(Errno::EINVAL.into());
600        };
601
602        // TODO: According to netlink(7), if the pid is zero, the kernel takes care of assigning
603        // it, but we will leave it untouched at the moment. We can implement the assignment
604        // later when we want to support it.
605        self.bound_addr = Some(*addr);
606
607        // According to netlink(7), if the groups is non-zero, it means that the socket wants to
608        // listen to some groups. If it includes unsupported groups, we will emit the error here.
609        if (addr.groups() & !(RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR)) != 0 {
610            log::warn!(
611                "Attempted to bind netlink socket to an address with unsupported groups {}",
612                addr.groups()
613            );
614            return Err(Errno::EINVAL.into());
615        }
616
617        Ok(())
618    }
619
620    fn sendmsg(
621        &mut self,
622        common: &mut NetlinkSocketCommon,
623        socket: &Arc<AtomicRefCell<NetlinkSocket>>,
624        args: SendmsgArgs,
625        mem: &mut MemoryManager,
626        cb_queue: &mut CallbackQueue,
627    ) -> Result<libc::ssize_t, SyscallError> {
628        if !args.control_ptr.ptr().is_null() {
629            log::debug!("Netlink sockets don't yet support control data for sendmsg()");
630            return Err(Errno::EINVAL.into());
631        }
632
633        // It's okay to not have a destination address
634        if let Some(addr) = args.addr {
635            // Parse the address
636            let Some(addr) = addr.as_netlink() else {
637                log::warn!("Attempted to send to non-netlink address {:?}", args.addr);
638                return Err(Errno::EINVAL.into());
639            };
640            // Sending to non-kernel address is not supported
641            if addr.pid() != 0 {
642                log::warn!("Attempted to send to non-kernel netlink address {addr:?}");
643                return Err(Errno::EINVAL.into());
644            }
645            // Sending to groups is not supported
646            if addr.groups() != 0 {
647                log::warn!("Attempted to send to netlink groups {addr:?}");
648                return Err(Errno::EINVAL.into());
649            }
650        }
651
652        let rv = common.sendmsg(socket, args.iovs, args.flags, mem, cb_queue)?;
653
654        self.refresh_file_state(common, FileSignals::empty(), cb_queue);
655
656        Ok(rv.try_into().unwrap())
657    }
658
659    fn recvmsg(
660        &mut self,
661        common: &mut NetlinkSocketCommon,
662        socket: &Arc<AtomicRefCell<NetlinkSocket>>,
663        args: RecvmsgArgs,
664        mem: &mut MemoryManager,
665        cb_queue: &mut CallbackQueue,
666    ) -> Result<RecvmsgReturn, SyscallError> {
667        if !args.control_ptr.ptr().is_null() {
668            log::debug!("Netlink sockets don't yet support control data for recvmsg()");
669            return Err(Errno::EINVAL.into());
670        }
671        let Some(flags) = MsgFlags::from_bits(args.flags) else {
672            warn_once_then_debug!("Unrecognized recv flags: {:#b}", args.flags);
673            return Err(Errno::EINVAL.into());
674        };
675
676        let mut packet_buffer = Vec::new();
677        let (_rv, _num_removed_from_buf) =
678            common.recvmsg(socket, &mut packet_buffer, flags, mem, cb_queue)?;
679        self.refresh_file_state(common, FileSignals::empty(), cb_queue);
680
681        let mut writer = IoVecWriter::new(args.iovs, mem);
682
683        // We set the source address as the netlink address of the kernel
684        let src_addr = SockaddrStorage::from_netlink(&NetlinkAddr::new(0, 0));
685
686        if packet_buffer.len() < std::mem::size_of::<nlmsghdr>() {
687            log::warn!("The processed packet is too short");
688            return Err(Errno::EINVAL.into());
689        }
690
691        let buffer = {
692            let nlmsg_type = &packet_buffer[memoffset::span_of!(nlmsghdr, nlmsg_type)];
693            let nlmsg_type = u16::from_ne_bytes(nlmsg_type.try_into().unwrap());
694
695            match nlmsg_type {
696                RTM_GETLINK => {
697                    let nlmsghdr_len = std::mem::size_of::<nlmsghdr>();
698                    let ifinfomsg_len = std::mem::size_of::<ifinfomsg>();
699                    let header_len = nlmsghdr_len + ifinfomsg_len;
700
701                    // Pad the message if it's too short and update the len field
702                    //
703                    // We typically try not to zero-fill structs when the bytes are missing,
704                    // but it should be okay here since we don't yet support most of the fields
705                    // of ifinfomsg
706                    if (nlmsghdr_len..header_len).contains(&packet_buffer.len()) {
707                        log::debug!(
708                            "Padding the RTM_GETLINK with zeroes to meet the minimum length"
709                        );
710                        packet_buffer.resize(header_len, 0);
711                        packet_buffer[memoffset::span_of!(nlmsghdr, nlmsg_len)]
712                            .copy_from_slice(&(header_len as u32).to_ne_bytes()[..]);
713                    }
714                    self.handle_ifinfomsg(common, &packet_buffer[..])
715                }
716                RTM_GETADDR => {
717                    let nlmsghdr_len = std::mem::size_of::<nlmsghdr>();
718                    let ifaddrmsg_len = std::mem::size_of::<ifaddrmsg>();
719                    let header_len = nlmsghdr_len + ifaddrmsg_len;
720
721                    // Pad the message if it's too short and update the len field
722                    //
723                    // We typically try not to zero-fill structs when the bytes are missing,
724                    // but it should be okay here since we don't yet support most of the fields
725                    // of ifaddrmsg
726                    if (nlmsghdr_len..header_len).contains(&packet_buffer.len()) {
727                        log::debug!(
728                            "Padding the RTM_GETADDR with zeroes to meet the minimum length"
729                        );
730                        packet_buffer.resize(header_len, 0);
731                        packet_buffer[memoffset::span_of!(nlmsghdr, nlmsg_len)]
732                            .copy_from_slice(&(header_len as u32).to_ne_bytes()[..]);
733                    }
734                    self.handle_ifaddrmsg(common, &packet_buffer[..])
735                }
736                _ => {
737                    warn_once_then_debug!(
738                        "Found unsupported nlmsg_type: {nlmsg_type} (only RTM_GETLINK
739                        and RTM_GETADDR are supported)"
740                    );
741                    self.handle_error(&packet_buffer[..])
742                }
743            }
744        };
745
746        // Try to write as much as we can. If the buffer is too small, just discard the rest
747        let mut total_copied = 0;
748        let mut buf = buffer.as_slice();
749        while !buf.is_empty() {
750            match writer.write(buf) {
751                Ok(0) => break,
752                Ok(n) => {
753                    buf = &buf[n..];
754                    total_copied += n;
755                }
756                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
757                Err(e) => return Err(e.into()),
758            }
759        }
760
761        let return_val = if flags.contains(MsgFlags::MSG_TRUNC) {
762            buffer.len()
763        } else {
764            total_copied
765        };
766
767        Ok(RecvmsgReturn {
768            return_val: return_val.try_into().unwrap(),
769            addr: Some(src_addr),
770            msg_flags: 0,
771            control_len: 0,
772        })
773    }
774
775    fn handle_error(&self, bytes: &[u8]) -> Vec<u8> {
776        // If we can't get the pid, set it to zero
777        let nlmsg_seq = match bytes.get(memoffset::span_of!(nlmsghdr, nlmsg_seq)) {
778            Some(x) => u32::from_ne_bytes(x.try_into().unwrap()),
779            None => 0,
780        };
781
782        // Generate a dummy error with the same sequence number as the request
783        let msg = NlmsghdrBuilder::default()
784            .nl_type(Nlmsg::Error)
785            .nl_flags(NlmF::empty())
786            .nl_seq(nlmsg_seq)
787            .nl_payload(NlPayload::<Nlmsg, ()>::Empty)
788            .build()
789            .expect("NlmsghdrBuilder missing a required field");
790
791        let mut buffer = Cursor::new(Vec::new());
792        msg.to_bytes(&mut buffer).unwrap();
793        buffer.into_inner()
794    }
795
796    fn handle_ifaddrmsg(&self, common: &mut NetlinkSocketCommon, bytes: &[u8]) -> Vec<u8> {
797        let Ok(nlmsg) = Nlmsghdr::<Rtm, Ifaddrmsg>::from_bytes(&mut Cursor::new(bytes)) else {
798            log::warn!("Failed to deserialize the message");
799            return self.handle_error(bytes);
800        };
801
802        let Some(ifaddrmsg) = nlmsg.get_payload() else {
803            log::warn!("Failed to find the payload");
804            return self.handle_error(bytes);
805        };
806
807        // The only supported interface address family is AF_INET
808        if *ifaddrmsg.ifa_family() != RtAddrFamily::Unspecified
809            && *ifaddrmsg.ifa_family() != RtAddrFamily::Inet
810        {
811            log::warn!("Unsupported ifa_family (only AF_UNSPEC and AF_INET are supported)");
812            return self.handle_error(bytes);
813        }
814
815        // The rest of the fields are unsupported. We limit only the interest to the zero values
816        if *ifaddrmsg.ifa_prefixlen() != 0
817            || !ifaddrmsg.ifa_flags().is_empty()
818            || *ifaddrmsg.ifa_index() != 0
819            || *ifaddrmsg.ifa_scope() != RtScope::Universe
820        {
821            log::warn!(
822                "Unsupported ifa_prefixlen, ifa_flags, ifa_scope, or ifa_index (they have to be 0)",
823            );
824            return self.handle_error(bytes);
825        }
826
827        let mut buffer = Cursor::new(Vec::new());
828        // Send the interface addresses
829        for interface in &common.interfaces {
830            let address = interface.address.octets();
831            let broadcast = Ipv4Addr::from(
832                0xffff_ffff_u32
833                    .checked_shr(u32::from(interface.prefix_len))
834                    .unwrap_or(0)
835                    | u32::from(interface.address),
836            )
837            .octets();
838            let mut label = Vec::from(interface.label.as_bytes());
839            label.push(0); // Null-terminate
840
841            // List of attribtes sent with the response for the current interface
842            let attrs = [
843                // I don't know the difference between IFA_ADDRESS and IFA_LOCAL. However, Linux
844                // provides the same address for both attributes, so I do the same.
845                // Run `strace ip addr` to see.
846                RtattrBuilder::default()
847                    .rta_type(Ifa::Address)
848                    .rta_payload(Buffer::from(&address[..]))
849                    .build()
850                    .unwrap(),
851                RtattrBuilder::default()
852                    .rta_type(Ifa::Local)
853                    .rta_payload(Buffer::from(&address[..]))
854                    .build()
855                    .unwrap(),
856                RtattrBuilder::default()
857                    .rta_type(Ifa::Broadcast)
858                    .rta_payload(Buffer::from(&broadcast[..]))
859                    .build()
860                    .unwrap(),
861                RtattrBuilder::default()
862                    .rta_type(Ifa::Label)
863                    .rta_payload(Buffer::from(label))
864                    .build()
865                    .unwrap(),
866            ];
867            let ifaddrmsg = IfaddrmsgBuilder::default()
868                .ifa_family(RtAddrFamily::Inet)
869                .ifa_prefixlen(interface.prefix_len)
870                // IFA_F_PERMANENT is used to indicate that the address is permanent
871                .ifa_flags(IfaF::PERMANENT)
872                .ifa_scope(interface.scope)
873                .ifa_index(interface.index)
874                .rtattrs(RtBuffer::from_iter(attrs))
875                .build()
876                .expect("IfaddrmsgBuilder missing a required field");
877            let nlmsg = NlmsghdrBuilder::default()
878                .nl_type(Rtm::Newaddr)
879                // The NLM_F_MULTI flag is used to indicate that we will send multiple messages
880                .nl_flags(NlmF::MULTI)
881                // Use the same sequence number as the request
882                .nl_seq(*nlmsg.nl_seq())
883                .nl_payload(NlPayload::Payload(ifaddrmsg))
884                .build()
885                .expect("NlmsghdrBuilder missing a required field");
886            nlmsg.to_bytes(&mut buffer).unwrap();
887        }
888        // After sending the messages with the NLM_F_MULTI flag set, we need to send the NLMSG_DONE message
889        let done_msg = NlmsghdrBuilder::default()
890            .nl_type(Nlmsg::Done)
891            .nl_flags(NlmF::MULTI)
892            // Use the same sequence number as the request
893            .nl_seq(*nlmsg.nl_seq())
894            // Linux also emits the errno of zero after the header. See `strace ip addr`.
895            // For documentation reference, see:
896            // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/userspace-api/netlink/intro.rst?h=v6.2#n232
897            // For code reference, see:
898            // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/netlink/af_netlink.c?h=v6.2#n2222
899            .nl_payload(NlPayload::Payload(0u32))
900            .build()
901            .expect("NlmsghdrBuilder missing a required field");
902        done_msg.to_bytes(&mut buffer).unwrap();
903
904        buffer.into_inner()
905    }
906
907    fn handle_ifinfomsg(&self, common: &mut NetlinkSocketCommon, bytes: &[u8]) -> Vec<u8> {
908        let Ok(nlmsg) = Nlmsghdr::<Rtm, Ifinfomsg>::from_bytes(&mut Cursor::new(bytes)) else {
909            log::warn!("Failed to deserialize the message");
910            return self.handle_error(bytes);
911        };
912
913        let Some(ifinfomsg) = nlmsg.get_payload() else {
914            log::warn!("Failed to find the payload");
915            return self.handle_error(bytes);
916        };
917
918        // The only supported interface address family is AF_INET
919        if *ifinfomsg.ifi_family() != RtAddrFamily::Unspecified
920            && *ifinfomsg.ifi_family() != RtAddrFamily::Inet
921        {
922            warn_once_then_debug!(
923                "Unsupported ifi_family (only AF_UNSPEC and AF_INET are supported)"
924            );
925            return self.handle_error(bytes);
926        }
927
928        // The rest of the fields are unsupported. We limit only the interest to the zero values
929        if *ifinfomsg.ifi_type() != 0.into()
930            || *ifinfomsg.ifi_index() != 0
931            || !ifinfomsg.ifi_flags().is_empty()
932        {
933            warn_once_then_debug!(
934                "Unsupported ifi_type, ifi_index, or ifi_flags (they have to be 0)"
935            );
936            return self.handle_error(bytes);
937        }
938
939        // We don't check for ifi_change because we found that `ip addr` sets it to zero even if
940        // rtnetlink(7) recommends to set it to all 1s
941
942        let mut buffer = Cursor::new(Vec::new());
943        // Send the interface addresses
944        for interface in &common.interfaces {
945            let mut label = Vec::from(interface.label.as_bytes());
946            label.push(0); // Null-terminate
947
948            // List of attribtes sent with the response for the current interface
949            let attrs = [
950                RtattrBuilder::default()
951                    .rta_type(Ifla::Ifname)
952                    .rta_payload(Buffer::from(label))
953                    .build()
954                    .unwrap(),
955                // Not sure about the value of this one, but I always see 1000 from `ip addr`. If
956                // we don't specify this, `ip addr` will create an AF_INET socket and do ioctl. See
957                // https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/ipaddress.c#n168
958                RtattrBuilder::default()
959                    .rta_type(Ifla::Txqlen)
960                    .rta_payload(Buffer::from(&u32::to_le_bytes(1000)[..]))
961                    .build()
962                    .unwrap(),
963                RtattrBuilder::default()
964                    .rta_type(Ifla::Mtu)
965                    .rta_payload(Buffer::from(&u32::to_le_bytes(interface.mtu)[..]))
966                    .build()
967                    .unwrap(),
968                // TODO: Add the MAC address through IFLA_ADDRESS and IFLA_BROADCAST
969            ];
970            let flags = if interface.if_type == Arphrd::Loopback {
971                Iff::UP | Iff::LOOPBACK | Iff::RUNNING
972            } else {
973                // Not sure about the IFF_MULTICAST, but it's also the one I got from `strace ip addr`
974                Iff::UP | Iff::BROADCAST | Iff::RUNNING | Iff::MULTICAST
975            };
976            let interface_index = interface
977                .index
978                .try_into()
979                .expect("interface index too large");
980
981            let ifinfomsg = IfinfomsgBuilder::default()
982                .ifi_family(RtAddrFamily::Inet)
983                .ifi_type(interface.if_type)
984                .ifi_index(interface_index)
985                .ifi_flags(flags)
986                // rtnetlink(7) recommends to set it to all 1s
987                .ifi_change(Iff::from_bits_retain(0xffffffff))
988                .rtattrs(RtBuffer::from_iter(attrs))
989                .build()
990                .expect("IfinfomsgBuilder missing a required field");
991            let nlmsg = NlmsghdrBuilder::default()
992                .nl_type(Rtm::Newlink)
993                // The NLM_F_MULTI flag is used to indicate that we will send multiple messages
994                .nl_flags(NlmF::MULTI)
995                // Use the same sequence number as the request
996                .nl_seq(*nlmsg.nl_seq())
997                .nl_payload(NlPayload::Payload(ifinfomsg))
998                .build()
999                .expect("NlmsghdrBuilder missing a required field");
1000            nlmsg.to_bytes(&mut buffer).unwrap();
1001        }
1002        // After sending the messages with the NLM_F_MULTI flag set, we need to send the NLMSG_DONE message
1003        let done_msg = NlmsghdrBuilder::default()
1004            .nl_type(Nlmsg::Done)
1005            .nl_flags(NlmF::MULTI)
1006            // Use the same sequence number as the request
1007            .nl_seq(*nlmsg.nl_seq())
1008            // Linux also emits the errno of zero after the header. See `strace ip addr`.
1009            // For documentation reference, see:
1010            // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/userspace-api/netlink/intro.rst?h=v6.2#n232
1011            // For code reference, see:
1012            // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/netlink/af_netlink.c?h=v6.2#n2222
1013            .nl_payload(NlPayload::Payload(0u32))
1014            .build()
1015            .expect("NlmsghdrBuilder missing a required field");
1016        done_msg.to_bytes(&mut buffer).unwrap();
1017
1018        buffer.into_inner()
1019    }
1020}
1021
1022impl ClosedState {
1023    fn bound_address(&self) -> Result<Option<NetlinkAddr>, Errno> {
1024        Ok(None)
1025    }
1026
1027    fn refresh_file_state(
1028        &self,
1029        common: &mut NetlinkSocketCommon,
1030        signals: FileSignals,
1031        cb_queue: &mut CallbackQueue,
1032    ) {
1033        common.update_state(
1034            /* mask= */ FileState::all(),
1035            FileState::CLOSED,
1036            signals,
1037            cb_queue,
1038        );
1039    }
1040
1041    fn close(
1042        self,
1043        _common: &mut NetlinkSocketCommon,
1044        _cb_queue: &mut CallbackQueue,
1045    ) -> (ProtocolState, Result<(), SyscallError>) {
1046        // why are we trying to close an already closed file? we probably want a bt here...
1047        panic!("Trying to close an already closed socket");
1048    }
1049
1050    fn bind(
1051        &mut self,
1052        _common: &mut NetlinkSocketCommon,
1053        _socket: &Arc<AtomicRefCell<NetlinkSocket>>,
1054        _addr: Option<&SockaddrStorage>,
1055        _rng: impl rand::Rng,
1056    ) -> Result<(), SyscallError> {
1057        // We follow the same approach as UnixSocket
1058        log::warn!("bind() while in state {}", std::any::type_name::<Self>());
1059        Err(Errno::EOPNOTSUPP.into())
1060    }
1061
1062    fn sendmsg(
1063        &mut self,
1064        _common: &mut NetlinkSocketCommon,
1065        _socket: &Arc<AtomicRefCell<NetlinkSocket>>,
1066        _args: SendmsgArgs,
1067        _mem: &mut MemoryManager,
1068        _cb_queue: &mut CallbackQueue,
1069    ) -> Result<libc::ssize_t, SyscallError> {
1070        // We follow the same approach as UnixSocket
1071        log::warn!("sendmsg() while in state {}", std::any::type_name::<Self>());
1072        Err(Errno::EOPNOTSUPP.into())
1073    }
1074
1075    fn recvmsg(
1076        &mut self,
1077        _common: &mut NetlinkSocketCommon,
1078        _socket: &Arc<AtomicRefCell<NetlinkSocket>>,
1079        _args: RecvmsgArgs,
1080        _mem: &mut MemoryManager,
1081        _cb_queue: &mut CallbackQueue,
1082    ) -> Result<RecvmsgReturn, SyscallError> {
1083        // We follow the same approach as UnixSocket
1084        log::warn!("recvmsg() while in state {}", std::any::type_name::<Self>());
1085        Err(Errno::EOPNOTSUPP.into())
1086    }
1087}
1088
1089// The struct used to describe the network interface
1090struct Interface {
1091    address: Ipv4Addr,
1092    label: String,
1093    prefix_len: u8,
1094    if_type: Arphrd,
1095    mtu: u32,
1096    scope: RtScope,
1097    index: libc::c_uint,
1098}
1099
1100/// Common data and functionality that is useful for all states.
1101struct NetlinkSocketCommon {
1102    buffer: Arc<AtomicRefCell<SharedBuf>>,
1103    /// The max number of "in flight" bytes (sent but not yet read from the receiving socket).
1104    send_limit: u64,
1105    /// The number of "in flight" bytes.
1106    sent_len: u64,
1107    event_source: StateEventSource,
1108    state: FileState,
1109    status: FileStatus,
1110    // should only be used by `OpenFile` to make sure there is only ever one `OpenFile` instance for
1111    // this file
1112    has_open_file: bool,
1113    /// Interfaces
1114    interfaces: Vec<Interface>,
1115}
1116
1117impl NetlinkSocketCommon {
1118    pub fn supports_sa_restart(&self) -> bool {
1119        true
1120    }
1121
1122    pub fn sendmsg(
1123        &mut self,
1124        socket: &Arc<AtomicRefCell<NetlinkSocket>>,
1125        iovs: &[IoVec],
1126        flags: libc::c_int,
1127        mem: &mut MemoryManager,
1128        cb_queue: &mut CallbackQueue,
1129    ) -> Result<usize, SyscallError> {
1130        // MSG_NOSIGNAL is a no-op, since netlink sockets are not stream-oriented.
1131        // Ignore the MSG_TRUNC flag since it doesn't do anything when sending.
1132        let supported_flags = MsgFlags::MSG_DONTWAIT | MsgFlags::MSG_NOSIGNAL | MsgFlags::MSG_TRUNC;
1133
1134        // if there's a flag we don't support, it's probably best to raise an error rather than do
1135        // the wrong thing
1136        let Some(mut flags) = MsgFlags::from_bits(flags) else {
1137            warn_once_then_debug!("Unrecognized send flags: {:#b}", flags);
1138            return Err(Errno::EINVAL.into());
1139        };
1140        if flags.intersects(!supported_flags) {
1141            warn_once_then_debug!("Unsupported send flags: {:?}", flags);
1142            return Err(Errno::EINVAL.into());
1143        }
1144
1145        if self.status.contains(FileStatus::NONBLOCK) {
1146            flags.insert(MsgFlags::MSG_DONTWAIT);
1147        }
1148
1149        // run in a closure so that an early return doesn't return from the syscall handler
1150        let result = (|| {
1151            let len = iovs.iter().map(|x| x.len).sum::<libc::size_t>();
1152
1153            // we keep track of the send buffer size manually, since the netlink socket buffers all
1154            // have usize::MAX length
1155            let space_available = self
1156                .send_limit
1157                .saturating_sub(self.sent_len)
1158                .try_into()
1159                .unwrap();
1160
1161            if space_available == 0 {
1162                return Err(Errno::EAGAIN);
1163            }
1164
1165            if len > space_available {
1166                if len <= self.send_limit.try_into().unwrap() {
1167                    // we can send this when the buffer has more space available
1168                    return Err(Errno::EAGAIN);
1169                } else {
1170                    // we could never send this message
1171                    return Err(Errno::EMSGSIZE);
1172                }
1173            }
1174
1175            let reader = IoVecReader::new(iovs, mem);
1176            let reader = reader.take(len.try_into().unwrap());
1177
1178            // send the packet directly to the buffer of the socket so that it will be
1179            // processed when the socket is read.
1180            self.buffer
1181                .borrow_mut()
1182                .write_packet(reader, len, cb_queue)
1183                .map_err(|e| Errno::try_from(e).unwrap())?;
1184
1185            // if we successfully sent bytes, update the sent count
1186            self.sent_len += u64::try_from(len).unwrap();
1187            Ok(len)
1188        })();
1189
1190        // if the syscall would block and we don't have the MSG_DONTWAIT flag
1191        if result.as_ref().err() == Some(&Errno::EWOULDBLOCK)
1192            && !flags.contains(MsgFlags::MSG_DONTWAIT)
1193        {
1194            return Err(SyscallError::new_blocked_on_file(
1195                File::Socket(Socket::Netlink(socket.clone())),
1196                FileState::WRITABLE,
1197                self.supports_sa_restart(),
1198            ));
1199        }
1200
1201        Ok(result?)
1202    }
1203
1204    pub fn recvmsg<W: Write>(
1205        &mut self,
1206        socket: &Arc<AtomicRefCell<NetlinkSocket>>,
1207        dst: W,
1208        mut flags: MsgFlags,
1209        _mem: &mut MemoryManager,
1210        cb_queue: &mut CallbackQueue,
1211    ) -> Result<(usize, usize), SyscallError> {
1212        let supported_flags = MsgFlags::MSG_DONTWAIT | MsgFlags::MSG_PEEK | MsgFlags::MSG_TRUNC;
1213
1214        // if there's a flag we don't support, it's probably best to raise an error rather than do
1215        // the wrong thing
1216        if flags.intersects(!supported_flags) {
1217            warn_once_then_debug!("Unsupported recv flags: {:?}", flags);
1218            return Err(Errno::EINVAL.into());
1219        }
1220
1221        if self.status.contains(FileStatus::NONBLOCK) {
1222            flags.insert(MsgFlags::MSG_DONTWAIT);
1223        }
1224
1225        // run in a closure so that an early return doesn't return from the syscall handler
1226        let result = (|| {
1227            let mut buffer = self.buffer.borrow_mut();
1228
1229            // the read would block if the buffer has no data
1230            if !buffer.has_data() {
1231                return Err(Errno::EWOULDBLOCK);
1232            }
1233
1234            let (num_copied, num_removed_from_buf) = if flags.contains(MsgFlags::MSG_PEEK) {
1235                buffer.peek(dst).map_err(|e| Errno::try_from(e).unwrap())?
1236            } else {
1237                buffer
1238                    .read(dst, cb_queue)
1239                    .map_err(|e| Errno::try_from(e).unwrap())?
1240            };
1241
1242            if flags.contains(MsgFlags::MSG_TRUNC) {
1243                // return the total size of the message, not the number of bytes we read
1244                Ok((num_removed_from_buf, num_removed_from_buf))
1245            } else {
1246                Ok((num_copied, num_removed_from_buf))
1247            }
1248        })();
1249
1250        // if the syscall would block and we don't have the MSG_DONTWAIT flag
1251        if result.as_ref().err() == Some(&Errno::EWOULDBLOCK)
1252            && !flags.contains(MsgFlags::MSG_DONTWAIT)
1253        {
1254            return Err(SyscallError::new_blocked_on_file(
1255                File::Socket(Socket::Netlink(socket.clone())),
1256                FileState::READABLE,
1257                self.supports_sa_restart(),
1258            ));
1259        }
1260
1261        Ok(result?)
1262    }
1263
1264    fn update_state(
1265        &mut self,
1266        mask: FileState,
1267        state: FileState,
1268        signals: FileSignals,
1269        cb_queue: &mut CallbackQueue,
1270    ) {
1271        let old_state = self.state;
1272
1273        // remove the masked flags, then copy the masked flags
1274        self.state.remove(mask);
1275        self.state.insert(state & mask);
1276
1277        self.handle_state_change(old_state, signals, cb_queue);
1278    }
1279
1280    fn handle_state_change(
1281        &mut self,
1282        old_state: FileState,
1283        signals: FileSignals,
1284        cb_queue: &mut CallbackQueue,
1285    ) {
1286        let states_changed = self.state ^ old_state;
1287
1288        // if nothing changed
1289        if states_changed.is_empty() && signals.is_empty() {
1290            return;
1291        }
1292
1293        self.event_source
1294            .notify_listeners(self.state, states_changed, signals, cb_queue);
1295    }
1296}
1297
1298#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
1299pub enum NetlinkSocketType {
1300    Dgram,
1301    Raw,
1302}
1303
1304impl TryFrom<libc::c_int> for NetlinkSocketType {
1305    type Error = NetlinkSocketTypeConversionError;
1306    fn try_from(val: libc::c_int) -> Result<Self, Self::Error> {
1307        match val {
1308            libc::SOCK_DGRAM => Ok(Self::Dgram),
1309            libc::SOCK_RAW => Ok(Self::Raw),
1310            x => Err(NetlinkSocketTypeConversionError(x)),
1311        }
1312    }
1313}
1314
1315#[derive(Copy, Clone, Debug)]
1316pub struct NetlinkSocketTypeConversionError(libc::c_int);
1317
1318impl std::error::Error for NetlinkSocketTypeConversionError {}
1319
1320impl std::fmt::Display for NetlinkSocketTypeConversionError {
1321    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1322        write!(
1323            f,
1324            "Invalid socket type {}; netlink sockets only support SOCK_DGRAM and SOCK_RAW",
1325            self.0
1326        )
1327    }
1328}
1329
1330#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
1331pub enum NetlinkFamily {
1332    Route,
1333}
1334
1335impl TryFrom<libc::c_int> for NetlinkFamily {
1336    type Error = NetlinkFamilyConversionError;
1337    fn try_from(val: libc::c_int) -> Result<Self, Self::Error> {
1338        match val {
1339            libc::NETLINK_ROUTE => Ok(Self::Route),
1340            x => Err(NetlinkFamilyConversionError(x)),
1341        }
1342    }
1343}
1344
1345#[derive(Copy, Clone, Debug)]
1346pub struct NetlinkFamilyConversionError(libc::c_int);
1347
1348impl std::error::Error for NetlinkFamilyConversionError {}
1349
1350impl std::fmt::Display for NetlinkFamilyConversionError {
1351    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1352        write!(
1353            f,
1354            "Invalid netlink family {}; netlink families only support NETLINK_ROUTE",
1355            self.0
1356        )
1357    }
1358}