Skip to main content

starnix_core/vfs/socket/
socket_backed_by_zxio.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::bpf::attachments::{SockAddrOp, SockAddrProgramResult, SockOp, SockProgramResult};
6use crate::fs::fuchsia::zxio::{zxio_query_events, zxio_wait_async};
7use crate::mm::MemoryAccessorExt;
8use crate::security;
9use crate::task::syscalls::SockFProgPtr;
10use crate::task::{CurrentTask, EventHandler, Kernel, Task, WaitCanceler, Waiter};
11use crate::vfs::socket::socket::ReadFromSockOptValue as _;
12use crate::vfs::socket::{
13    SockOptValue, Socket, SocketAddress, SocketDomain, SocketHandle, SocketMessageFlags, SocketOps,
14    SocketPeer, SocketProtocol, SocketShutdownFlags, SocketType,
15};
16use crate::vfs::{AncillaryData, FileObject, InputBuffer, MessageReadInfo, OutputBuffer};
17use byteorder::ByteOrder;
18use ebpf::convert_and_verify_cbpf;
19use ebpf_api::SOCKET_FILTER_CBPF_CONFIG;
20use fidl::endpoints::DiscoverableProtocolMarker as _;
21use fidl_fuchsia_net_resources as fnet_resources;
22use fidl_fuchsia_posix_socket as fposix_socket;
23use fidl_fuchsia_posix_socket_packet as fposix_socket_packet;
24use fidl_fuchsia_posix_socket_raw as fposix_socket_raw;
25use linux_uapi::{IP_MULTICAST_ALL, IP_PASSSEC};
26use starnix_logging::{log_error, log_warn, track_stub};
27use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
28use starnix_uapi::auth::{CAP_NET_ADMIN, CAP_NET_RAW};
29use starnix_uapi::errors::{ENOTSUP, Errno, ErrnoCode};
30use starnix_uapi::user_address::{UserAddress, UserRef};
31use starnix_uapi::vfs::FdEvents;
32use starnix_uapi::{
33    AF_PACKET, BPF_MAXINSNS, FIONREAD, MSG_DONTWAIT, MSG_WAITALL, SO_ATTACH_FILTER,
34    SO_BINDTODEVICE, SO_BINDTOIFINDEX, SO_COOKIE, c_int, errno, errno_from_zxio_code, error,
35    from_status_like_fdio, sock_filter, uapi, ucred, uid_t,
36};
37use static_assertions::const_assert_eq;
38use std::mem::size_of;
39use std::sync::{Arc, OnceLock};
40use syncio::zxio::{
41    IP_RECVERR, IP_TRANSPARENT, SO_DOMAIN, SO_FUCHSIA_MARK, SO_MARK, SO_PROTOCOL, SO_REUSEPORT,
42    SO_TYPE, SOL_IP, SOL_SOCKET, ZXIO_SOCKET_MARK_DOMAIN_1, ZXIO_SOCKET_MARK_DOMAIN_2,
43    zxio_socket_mark,
44};
45use syncio::{
46    ControlMessage, RecvMessageInfo, ServiceConnector, Zxio, ZxioErrorCode,
47    ZxioSocketCreationOptions, ZxioSocketMark, ZxioWakeGroupToken,
48};
49use zerocopy::IntoBytes;
50
51/// Linux marks aren't compatible with Fuchsia marks, we store the `SO_MARK`
52/// value in the fuchsia `ZXIO_SOCKET_MARK_DOMAIN_1`. If a mark in this domain
53/// is absent, it will be reported to starnix applications as a `0` since that
54/// is the default mark value on Linux.
55pub const ZXIO_SOCKET_MARK_SO_MARK: u8 = ZXIO_SOCKET_MARK_DOMAIN_1;
56/// Fuchsia does not have uids, we use the `ZXIO_SOCKET_MARK_DOMAIN_2` on the
57/// socket to store the UID for the sockets created by starnix.
58pub const ZXIO_SOCKET_MARK_UID: u8 = ZXIO_SOCKET_MARK_DOMAIN_2;
59
60/// Connects to the appropriate `fuchsia_posix_socket_*::Provider` protocol.
61struct SocketProviderServiceConnector;
62
63impl ServiceConnector for SocketProviderServiceConnector {
64    fn connect(service_name: &str) -> Result<&'static zx::Channel, zx::Status> {
65        match service_name {
66            fposix_socket::ProviderMarker::PROTOCOL_NAME => {
67                static CHANNEL: OnceLock<Result<zx::Channel, zx::Status>> = OnceLock::new();
68                &CHANNEL
69            }
70            fposix_socket_packet::ProviderMarker::PROTOCOL_NAME => {
71                static CHANNEL: OnceLock<Result<zx::Channel, zx::Status>> = OnceLock::new();
72                &CHANNEL
73            }
74            fposix_socket_raw::ProviderMarker::PROTOCOL_NAME => {
75                static CHANNEL: OnceLock<Result<zx::Channel, zx::Status>> = OnceLock::new();
76                &CHANNEL
77            }
78            _ => return Err(zx::Status::INTERNAL),
79        }
80        .get_or_init(|| {
81            let (client, server) = zx::Channel::create();
82            let protocol_path = format!("/svc/{service_name}");
83            fdio::service_connect(&protocol_path, server)?;
84            Ok(client)
85        })
86        .as_ref()
87        .map_err(|status| *status)
88    }
89}
90
91// Trait for types that can be converted to a byte vector that contains a
92// `sockaddr` value.
93trait AsSockAddrBytes {
94    fn as_sockaddr_bytes(&self) -> Result<&[u8], Errno>;
95}
96
97impl AsSockAddrBytes for &SocketAddress {
98    fn as_sockaddr_bytes(&self) -> Result<&[u8], Errno> {
99        match self {
100            SocketAddress::Inet(addr) => Ok(&addr[..]),
101            SocketAddress::Inet6(addr) => Ok(&addr[..]),
102            _ => error!(EAFNOSUPPORT),
103        }
104    }
105}
106
107impl AsSockAddrBytes for &Vec<u8> {
108    fn as_sockaddr_bytes(&self) -> Result<&[u8], Errno> {
109        Ok(self.as_slice())
110    }
111}
112
113/// A socket backed by an underlying Zircon I/O object.
114pub struct ZxioBackedSocket {
115    /// The underlying Zircon I/O object.
116    zxio: syncio::Zxio,
117
118    // SO_COOKIE cache.
119    cookie: OnceLock<u64>,
120
121    // Token resolver for this socket.
122    token_resolver: Arc<SocketTokenResolver>,
123
124    // UID of the process that created socket.
125    uid: uid_t,
126}
127
128impl ZxioBackedSocket {
129    pub fn new(
130        current_task: &CurrentTask,
131        domain: SocketDomain,
132        socket_type: SocketType,
133        protocol: SocketProtocol,
134    ) -> Result<ZxioBackedSocket, Errno> {
135        let marks = &mut [
136            ZxioSocketMark::so_mark(0),
137            ZxioSocketMark::uid(current_task.current_creds().uid),
138        ];
139
140        match (domain, socket_type, protocol) {
141            (SocketDomain::Inet, SocketType::Datagram, SocketProtocol::ICMP)
142            | (SocketDomain::Inet6, SocketType::Datagram, SocketProtocol::ICMPV6) => {
143                let gid_range =
144                    current_task.kernel().system_limits.socket.icmp_ping_gids.lock().clone();
145                if !gid_range.contains(&current_task.current_creds().egid) {
146                    return error!(EACCES);
147                }
148            }
149            _ => (),
150        };
151
152        let wake_group = match current_task.kernel().netstack_wake_group() {
153            Some(fnet_resources::WakeGroupToken { token }) => token
154                .duplicate_handle(zx::Rights::SAME_RIGHTS)
155                .expect("duplicate handle to wake group"),
156            None => {
157                log_warn!("Netstack wake group not available. Failing socket creation");
158                // Make applications fail loudly because this shouldn't happen
159                // unless something is misconfigured or the netstack has died.
160                return error!(ENOTRECOVERABLE);
161            }
162        };
163
164        let zxio = Zxio::new_socket::<SocketProviderServiceConnector>(
165            domain.as_raw() as c_int,
166            socket_type.as_raw() as c_int,
167            protocol.as_raw() as c_int,
168            ZxioSocketCreationOptions {
169                marks,
170                wake_group: ZxioWakeGroupToken::new(Some(wake_group)),
171            },
172        )
173        .map_err(|status| from_status_like_fdio!(status))?
174        .map_err(|out_code| errno_from_zxio_code!(out_code))?;
175
176        let socket = Self::new_with_zxio(current_task, zxio);
177
178        if matches!(domain, SocketDomain::Inet | SocketDomain::Inet6) {
179            match current_task.kernel().ebpf_state.attachments.root_cgroup().run_sock_prog(
180                current_task,
181                SockOp::Create,
182                domain,
183                socket_type,
184                protocol,
185                &socket,
186            ) {
187                SockProgramResult::Allow => (),
188                SockProgramResult::Block => return error!(EPERM),
189            }
190        }
191
192        Ok(socket)
193    }
194
195    pub fn new_with_zxio(current_task: &CurrentTask, zxio: syncio::Zxio) -> ZxioBackedSocket {
196        let uid = current_task.current_creds().euid;
197        let token_resolver = current_task
198            .kernel()
199            .socket_tokens_store
200            .get_token_resolver(current_task.kernel(), uid);
201        ZxioBackedSocket { zxio, cookie: Default::default(), token_resolver, uid }
202    }
203
204    fn sendmsg(
205        &self,
206        socket: &Socket,
207        current_task: &CurrentTask,
208        addr: &Option<SocketAddress>,
209        data: &mut dyn InputBuffer,
210        cmsgs: Vec<ControlMessage>,
211        flags: SocketMessageFlags,
212    ) -> Result<usize, Errno> {
213        let mut addr = match addr {
214            Some(
215                SocketAddress::Inet(sockaddr)
216                | SocketAddress::Inet6(sockaddr)
217                | SocketAddress::Packet(sockaddr),
218            ) => sockaddr.clone(),
219            Some(_) => return error!(EINVAL),
220            None => vec![],
221        };
222
223        // Run `CGROUP_UDP[46]_SENDMSG` eBPF programs for `sendto()` and
224        // `sendmsg()` on UDP sockets. Not necessary for `send()` (i.e. when
225        // `addr` is empty).
226        if matches!(
227            (socket.domain, socket.socket_type),
228            (SocketDomain::Inet | SocketDomain::Inet6, SocketType::Datagram)
229        ) && addr.len() > 0
230        {
231            self.run_sockaddr_ebpf(socket, current_task, SockAddrOp::UdpSendMsg, &addr)?;
232        }
233
234        let map_errors = |res: Result<Result<usize, ZxioErrorCode>, zx::Status>| {
235            res.map_err(|status| match status {
236                zx::Status::OUT_OF_RANGE => errno!(EMSGSIZE),
237                other => from_status_like_fdio!(other),
238            })?
239            .map_err(|out_code| errno_from_zxio_code!(out_code))
240        };
241
242        let flags = flags.bits() & !MSG_DONTWAIT;
243        let sent_bytes = match data.peek_all_segments_as_iovecs() {
244            Ok(mut iovecs) => {
245                // Note: We have to prefault here because this is a C FFI call and we cannot
246                // catch faults directly like we do for Starnix-internal usercopies.
247                // In the future, we could look into implementing reactive faulting in
248                // `zxio_maybe_faultable_copy_impl` to match the behavior of internal
249                // usercopies.
250                let ranges =
251                    iovecs.as_ref().iter().filter(|iovec| iovec.iov_len > 0).map(|iovec| {
252                        (UserAddress::from_ptr(iovec.iov_base as usize), Some(iovec.iov_len))
253                    });
254                if let Ok(mm) = current_task.mm() {
255                    mm.ensure_ranges_mapped_in_user_vmar(ranges)?;
256                }
257
258                Some(map_errors(self.zxio.sendmsg(&mut addr, &mut iovecs, &cmsgs, flags))?)
259            }
260            Err(e) if e.code == ENOTSUP => None,
261            Err(e) => return Err(e),
262        };
263
264        // If we can't pass the iovecs directly so fallback to reading
265        // all the bytes from the input buffer first.
266        let sent_bytes = match sent_bytes {
267            Some(sent_bytes) => sent_bytes,
268            None => {
269                let mut bytes = data.peek_all()?;
270                map_errors(self.zxio.sendmsg(
271                    &mut addr,
272                    &mut [syncio::zxio::iovec {
273                        iov_base: bytes.as_mut_ptr() as *mut starnix_uapi::c_void,
274                        iov_len: bytes.len(),
275                    }],
276                    &cmsgs,
277                    flags,
278                ))?
279            }
280        };
281        data.advance(sent_bytes)?;
282        Ok(sent_bytes)
283    }
284
285    fn recvmsg(
286        &self,
287        socket: &Socket,
288        current_task: &CurrentTask,
289        data: &mut dyn OutputBuffer,
290        flags: SocketMessageFlags,
291    ) -> Result<RecvMessageInfo, Errno> {
292        let flags = flags.bits() & !MSG_DONTWAIT & !MSG_WAITALL;
293
294        let map_errors = |res: Result<Result<RecvMessageInfo, ZxioErrorCode>, zx::Status>| {
295            res.map_err(|status| from_status_like_fdio!(status))?
296                .map_err(|out_code| errno_from_zxio_code!(out_code))
297        };
298
299        let info = match data.peek_all_segments_as_iovecs() {
300            Ok(mut iovecs) => {
301                // Note: We have to prefault here because this is a C FFI call and we cannot
302                // catch faults directly like we do for Starnix-internal usercopies.
303                // In the future, we could look into implementing reactive faulting in
304                // `zxio_maybe_faultable_copy_impl` to match the behavior of internal
305                // usercopies.
306                let ranges =
307                    iovecs.as_ref().iter().filter(|iovec| iovec.iov_len > 0).map(|iovec| {
308                        (UserAddress::from_ptr(iovec.iov_base as usize), Some(iovec.iov_len))
309                    });
310                if let Ok(mm) = current_task.mm() {
311                    mm.ensure_ranges_mapped_in_user_vmar(ranges)?;
312                }
313
314                let info = map_errors(self.zxio.recvmsg(&mut iovecs, flags))?;
315                // SAFETY: we successfully read `info.bytes_read` bytes
316                // directly to the user's buffer segments.
317                (unsafe { data.advance(info.bytes_read) })?;
318                Some(info)
319            }
320            Err(e) if e.code == ENOTSUP => None,
321            Err(e) => return Err(e),
322        };
323
324        // If we can't pass the segments directly, fallback to receiving
325        // all the bytes in an intermediate buffer and writing that
326        // to our output buffer.
327        let info = match info {
328            Some(info) => info,
329            None => {
330                // TODO: use MaybeUninit
331                let mut buf = vec![0; data.available()];
332                let iovec = &mut [syncio::zxio::iovec {
333                    iov_base: buf.as_mut_ptr() as *mut starnix_uapi::c_void,
334                    iov_len: buf.len(),
335                }];
336                let info = map_errors(self.zxio.recvmsg(iovec, flags))?;
337                let written = data.write_all(&buf[..info.bytes_read])?;
338                debug_assert_eq!(written, info.bytes_read);
339                info
340            }
341        };
342
343        // Run eBPF programs for UDP sockets.
344        if matches!(
345            (socket.domain, socket.socket_type),
346            (SocketDomain::Inet | SocketDomain::Inet6, SocketType::Datagram)
347        ) {
348            self.run_sockaddr_ebpf(socket, current_task, SockAddrOp::UdpRecvMsg, &info.address)?;
349        }
350
351        Ok(info)
352    }
353
354    fn attach_cbpf_filter(&self, _task: &Task, code: Vec<sock_filter>) -> Result<(), Errno> {
355        // SO_ATTACH_FILTER is supported only for packet sockets.
356        let domain = self
357            .zxio
358            .getsockopt(SOL_SOCKET, SO_DOMAIN, size_of::<u32>() as u32)
359            .map_err(|status| from_status_like_fdio!(status))?
360            .map_err(|out_code| errno_from_zxio_code!(out_code))?;
361        let domain = u32::from_ne_bytes(domain.try_into().unwrap());
362        if domain != u32::from(AF_PACKET) {
363            return error!(ENOTSUP);
364        }
365
366        let program = convert_and_verify_cbpf(
367            &code,
368            ebpf_api::SOCKET_FILTER_SK_BUF_TYPE.clone(),
369            &SOCKET_FILTER_CBPF_CONFIG,
370        )
371        .map_err(|_| errno!(EINVAL))?;
372
373        // TODO(https://fxbug.dev/377332291) Use `zxio_borrow()` to avoid cloning the handle.
374        let packet_socket = fidl::endpoints::ClientEnd::<fposix_socket_packet::SocketMarker>::new(
375            self.zxio.clone_handle().map_err(|_| errno!(EIO))?.into(),
376        )
377        .into_sync_proxy();
378        let code: &[u64] = zerocopy::transmute_ref!(program.code());
379        let result = packet_socket.attach_bpf_filter_unsafe(code, zx::MonotonicInstant::INFINITE);
380        result.map_err(|_: fidl::Error| errno!(EIO))?.map_err(|e| {
381            Errno::with_context(
382                ErrnoCode::from_error_code(e.into_primitive() as i16),
383                "AttachBfpFilterUnsafe",
384            )
385        })
386    }
387
388    fn run_sockaddr_ebpf(
389        &self,
390        socket: &Socket,
391        current_task: &CurrentTask,
392        op: SockAddrOp,
393        socket_address: impl AsSockAddrBytes,
394    ) -> Result<(), Errno> {
395        // BPF_PROG_TYPE_CGROUP_SOCK_ADDR programs are executed only for IPv4 and IPv6 sockets.
396        if !matches!(socket.domain, SocketDomain::Inet | SocketDomain::Inet6) {
397            return Ok(());
398        }
399
400        let ebpf_result =
401            current_task.kernel().ebpf_state.attachments.root_cgroup().run_sock_addr_prog(
402                current_task,
403                op,
404                socket.domain,
405                socket.socket_type,
406                socket.protocol,
407                socket_address.as_sockaddr_bytes()?,
408                socket,
409            )?;
410        match ebpf_result {
411            SockAddrProgramResult::Allow => Ok(()),
412            SockAddrProgramResult::Block => error!(EPERM),
413        }
414    }
415
416    pub fn get_socket_cookie(&self) -> Result<u64, Errno> {
417        if let Some(cookie) = self.cookie.get() {
418            return Ok(*cookie);
419        }
420
421        let cookie = u64::from_ne_bytes(
422            self.zxio
423                .getsockopt(SOL_SOCKET, SO_COOKIE, size_of::<u64>() as u32)
424                .map_err(|status| from_status_like_fdio!(status))?
425                .map_err(|out_code| errno_from_zxio_code!(out_code))?
426                .try_into()
427                .unwrap(),
428        );
429        let _: Result<(), u64> = self.cookie.set(cookie);
430
431        return Ok(cookie);
432    }
433
434    pub fn uid(&self) -> uid_t {
435        self.uid
436    }
437}
438
439impl SocketOps for ZxioBackedSocket {
440    fn get_socket_info(&self) -> Result<(SocketDomain, SocketType, SocketProtocol), Errno> {
441        let getsockopt = |optname: u32| -> Result<u32, Errno> {
442            Ok(u32::from_ne_bytes(
443                self.zxio
444                    .getsockopt(SOL_SOCKET, optname, size_of::<u32>() as u32)
445                    .map_err(|status| from_status_like_fdio!(status))?
446                    .map_err(|out_code| errno_from_zxio_code!(out_code))?
447                    .try_into()
448                    .unwrap(),
449            ))
450        };
451
452        let domain_raw = getsockopt(SO_DOMAIN)?;
453        let domain = SocketDomain::from_raw(domain_raw.try_into().map_err(|_| errno!(EINVAL))?)
454            .ok_or_else(|| errno!(EINVAL))?;
455
456        let type_raw = getsockopt(SO_TYPE)?;
457        let socket_type = SocketType::from_raw(type_raw).ok_or_else(|| errno!(EINVAL))?;
458
459        let protocol_raw = getsockopt(SO_PROTOCOL)?;
460        let protocol = SocketProtocol::from_raw(protocol_raw);
461
462        Ok((domain, socket_type, protocol))
463    }
464
465    fn connect(
466        &self,
467        socket: &SocketHandle,
468        current_task: &CurrentTask,
469        peer: SocketPeer,
470    ) -> Result<(), Errno> {
471        match peer {
472            SocketPeer::Address(
473                ref address @ (SocketAddress::Inet(_) | SocketAddress::Inet6(_)),
474            ) => self.run_sockaddr_ebpf(socket, current_task, SockAddrOp::Connect, address)?,
475            _ => (),
476        };
477
478        let connect_result = match &peer {
479            SocketPeer::Address(
480                SocketAddress::Inet(addr)
481                | SocketAddress::Inet6(addr)
482                | SocketAddress::Packet(addr),
483            ) => self
484                .zxio
485                .connect(addr)
486                .map_err(|status| from_status_like_fdio!(status))?
487                .map_err(|out_code| errno_from_zxio_code!(out_code)),
488            SocketPeer::Address(SocketAddress::Unspecified) => {
489                if socket.socket_type == SocketType::Datagram {
490                    let unspec = uapi::sockaddr::default().as_bytes().to_vec();
491                    let res = self
492                        .zxio
493                        .connect(&unspec)
494                        .map_err(|status| from_status_like_fdio!(status))?
495                        .map_err(|out_code| errno_from_zxio_code!(out_code));
496                    match res {
497                        Ok(()) => Ok(()),
498                        Err(err)
499                            if err == errno!(EINVAL)
500                                || err == errno!(ENOTCONN)
501                                || err == errno!(EAFNOSUPPORT) =>
502                        {
503                            Ok(())
504                        }
505                        Err(err) => Err(err),
506                    }
507                } else {
508                    error!(EAFNOSUPPORT)
509                }
510            }
511            _ => error!(EINVAL),
512        };
513
514        if connect_result.is_ok() {
515            if let SocketPeer::Address(ref address) = peer {
516                if let Some(port) = address.maybe_inet_port() {
517                    if port == 80 {
518                        track_stub!(
519                            TODO("https://fxbug.dev/540841946"),
520                            "fake NFLOG message on port 80 connect"
521                        );
522                        let uid = current_task.current_creds().uid;
523                        crate::vfs::socket::send_fake_nflog_message(uid);
524                    }
525                }
526            }
527        }
528
529        connect_result
530    }
531
532    fn listen(&self, _socket: &Socket, backlog: i32, _credentials: ucred) -> Result<(), Errno> {
533        self.zxio
534            .listen(backlog)
535            .map_err(|status| from_status_like_fdio!(status))?
536            .map_err(|out_code| errno_from_zxio_code!(out_code))
537    }
538
539    fn accept(&self, socket: &Socket, current_task: &CurrentTask) -> Result<SocketHandle, Errno> {
540        let zxio = self
541            .zxio
542            .accept()
543            .map_err(|status| from_status_like_fdio!(status))?
544            .map_err(|out_code| errno_from_zxio_code!(out_code))?;
545
546        let accepted = Self::new_with_zxio(current_task, zxio);
547
548        // Clone sk_storage entries marked with BPF_F_CLONE.
549        fn log_cookie_error(err: &Errno) {
550            log_error!("Failed to get socket cookie: {err:?}");
551        }
552        let parent_cookie = self.get_socket_cookie().inspect_err(log_cookie_error);
553        let child_cookie = accepted.get_socket_cookie().inspect_err(log_cookie_error);
554        if let (Ok(parent_cookie), Ok(child_cookie)) = (parent_cookie, child_cookie) {
555            current_task.kernel().ebpf_state.clone_sk_storage_entries(parent_cookie, child_cookie);
556        }
557
558        Ok(Socket::new_with_ops_and_info(
559            Box::new(accepted),
560            socket.domain,
561            socket.socket_type,
562            socket.protocol,
563        ))
564    }
565
566    fn bind(
567        &self,
568        socket: &Socket,
569        current_task: &CurrentTask,
570        socket_address: SocketAddress,
571    ) -> Result<(), Errno> {
572        self.run_sockaddr_ebpf(socket, current_task, SockAddrOp::Bind, &socket_address)?;
573
574        match socket_address {
575            SocketAddress::Inet(addr)
576            | SocketAddress::Inet6(addr)
577            | SocketAddress::Packet(addr) => self
578                .zxio
579                .bind(&addr)
580                .map_err(|status| from_status_like_fdio!(status))?
581                .map_err(|out_code| errno_from_zxio_code!(out_code)),
582            _ => error!(EINVAL),
583        }
584    }
585
586    fn read(
587        &self,
588        socket: &Socket,
589        current_task: &CurrentTask,
590        data: &mut dyn OutputBuffer,
591        flags: SocketMessageFlags,
592    ) -> Result<MessageReadInfo, Errno> {
593        // MSG_ERRQUEUE is not supported for TCP sockets, but it's expected to fail with EAGAIN.
594        if socket.socket_type == SocketType::Stream && flags.contains(SocketMessageFlags::ERRQUEUE)
595        {
596            return error!(EAGAIN);
597        }
598
599        let mut info = self.recvmsg(socket, current_task, data, flags)?;
600
601        let bytes_read = info.bytes_read;
602
603        let address = if !info.address.is_empty() {
604            Some(SocketAddress::from_bytes(info.address)?)
605        } else {
606            None
607        };
608
609        Ok(MessageReadInfo {
610            bytes_read,
611            message_length: info.message_length,
612            address,
613            ancillary_data: info.control_messages.drain(..).map(AncillaryData::Ip).collect(),
614        })
615    }
616
617    fn write(
618        &self,
619        socket: &Socket,
620        current_task: &CurrentTask,
621        data: &mut dyn InputBuffer,
622        dest_address: &mut Option<SocketAddress>,
623        ancillary_data: &mut Vec<AncillaryData>,
624    ) -> Result<usize, Errno> {
625        let mut cmsgs = vec![];
626        for d in ancillary_data.drain(..) {
627            match d {
628                AncillaryData::Ip(msg) => cmsgs.push(msg),
629                _ => return error!(EINVAL),
630            }
631        }
632
633        // Ignore destination address if this is a stream socket.
634        let dest_address =
635            if socket.socket_type == SocketType::Stream { &None } else { dest_address };
636        self.sendmsg(socket, current_task, dest_address, data, cmsgs, SocketMessageFlags::empty())
637    }
638
639    fn wait_async(
640        &self,
641        _socket: &Socket,
642        _current_task: &CurrentTask,
643        waiter: &Waiter,
644        events: FdEvents,
645        handler: EventHandler,
646    ) -> WaitCanceler {
647        zxio_wait_async(&self.zxio, waiter, events, handler)
648    }
649
650    fn query_events(
651        &self,
652        _socket: &Socket,
653        _current_task: &CurrentTask,
654    ) -> Result<FdEvents, Errno> {
655        zxio_query_events(&self.zxio)
656    }
657
658    fn shutdown(&self, _socket: &Socket, how: SocketShutdownFlags) -> Result<(), Errno> {
659        self.zxio
660            .shutdown(how)
661            .map_err(|status| from_status_like_fdio!(status))?
662            .map_err(|out_code| errno_from_zxio_code!(out_code))
663    }
664
665    fn close(&self, current_task: &CurrentTask, socket: &Socket) {
666        if matches!(socket.domain, SocketDomain::Inet | SocketDomain::Inet6) {
667            // Invoke eBPF release program (if any). Result is ignored since we cannot block
668            // socket release.
669            let _: SockProgramResult =
670                current_task.kernel().ebpf_state.attachments.root_cgroup().run_sock_prog(
671                    current_task,
672                    SockOp::Release,
673                    socket.domain,
674                    socket.socket_type,
675                    socket.protocol,
676                    self,
677                );
678        }
679
680        let cookie = self.get_socket_cookie();
681
682        let _ = self.zxio.close();
683
684        // TODO(https://fxbug.dev/496639039): Move sk_storage cleanup to Netstack.
685        if let Ok(cookie) = cookie {
686            current_task.kernel().ebpf_state.remove_sk_storage_entries(cookie);
687        }
688    }
689
690    fn getsockname(&self, socket: &Socket) -> Result<SocketAddress, Errno> {
691        match self.zxio.getsockname() {
692            Err(_) | Ok(Err(_)) => Ok(SocketAddress::default_for_domain(socket.domain)),
693            Ok(Ok(addr)) => SocketAddress::from_bytes(addr),
694        }
695    }
696
697    fn getpeername(&self, _socket: &Socket) -> Result<SocketAddress, Errno> {
698        self.zxio
699            .getpeername()
700            .map_err(|status| from_status_like_fdio!(status))?
701            .map_err(|out_code| errno_from_zxio_code!(out_code))
702            .and_then(SocketAddress::from_bytes)
703    }
704
705    fn setsockopt(
706        &self,
707        _socket: &Socket,
708        current_task: &CurrentTask,
709        level: u32,
710        optname: u32,
711        optval: SockOptValue,
712    ) -> Result<(), Errno> {
713        match (level, optname) {
714            (SOL_SOCKET, SO_ATTACH_FILTER) => {
715                let fprog = SockFProgPtr::read_from_sockopt_value(current_task, &optval)?;
716                if fprog.len > BPF_MAXINSNS || fprog.len == 0 {
717                    return error!(EINVAL);
718                }
719                let code: Vec<sock_filter> = current_task
720                    .read_multi_arch_objects_to_vec(fprog.filter, fprog.len as usize)?;
721                return self.attach_cbpf_filter(current_task, code);
722            }
723            (SOL_IP, IP_RECVERR) => {
724                track_stub!(TODO("https://fxbug.dev/333060595"), "SOL_IP.IP_RECVERR");
725                return Ok(());
726            }
727            (SOL_IP, IP_MULTICAST_ALL) => {
728                track_stub!(TODO("https://fxbug.dev/404596095"), "SOL_IP.IP_MULTICAST_ALL");
729                return Ok(());
730            }
731            (SOL_IP, IP_PASSSEC) if current_task.kernel().features.selinux_test_suite => {
732                track_stub!(TODO("https://fxbug.dev/398663317"), "SOL_IP.IP_PASSSEC");
733                return Ok(());
734            }
735            (SOL_SOCKET, SO_MARK) => {
736                // Either `CAP_NET_RAW` or `CAP_NET_ADMIN` is required to set
737                // `SO_MARK`. If `CAP_NET_RAW` is not present, we then check
738                // `CAP_NET_ADMIN` using `check_task_capable`, which will
739                // generate an audit record if the capability is missing.
740                if !security::is_task_capable_noaudit(current_task, CAP_NET_RAW) {
741                    security::check_task_capable(current_task, CAP_NET_ADMIN)?;
742                }
743
744                let mark: u32 = optval.read(current_task)?;
745                let socket_mark = ZxioSocketMark::so_mark(mark);
746                let optval: &[u8; size_of::<zxio_socket_mark>()] =
747                    zerocopy::transmute_ref!(&socket_mark);
748                return self
749                    .zxio
750                    .setsockopt(SOL_SOCKET as i32, SO_FUCHSIA_MARK as i32, optval, None)
751                    .map_err(|status| from_status_like_fdio!(status))?
752                    .map_err(|out_code| errno_from_zxio_code!(out_code));
753            }
754            (SOL_SOCKET, SO_BINDTODEVICE | SO_BINDTOIFINDEX) => {
755                // Require `CAP_NET_RAW` to bind the socket to a device. This
756                // is consistent with Linux prior to 5.7. Starting from 5.7
757                // Linux allows requires this capability only if the socket
758                // is already bound to a device.
759                security::check_task_capable(current_task, CAP_NET_RAW).inspect_err(|_| {
760                    log_warn!(
761                        "setsockopt(SO_BINDTODEVICE) is called by a \
762                         process without CAP_NET_RAW: {:?}",
763                        current_task.thread_group(),
764                    )
765                })?;
766            }
767            (SOL_IP, IP_TRANSPARENT) => {
768                // Either `CAP_NET_RAW` or `CAP_NET_ADMIN` is required to set
769                // `IP_TRANSPARENT`. If `CAP_NET_RAW` is not present, we then
770                // check `CAP_NET_ADMIN` using `check_task_capable`, which will
771                // generate an audit record if the capability is missing.
772                if !security::is_task_capable_noaudit(current_task, CAP_NET_RAW) {
773                    security::check_task_capable(current_task, CAP_NET_ADMIN)?;
774                }
775            }
776            _ => {}
777        }
778
779        let optval = optval.to_vec(current_task)?;
780
781        let access_token = match (level, optname) {
782            (SOL_SOCKET, SO_REUSEPORT) => Some(self.token_resolver.get_sharing_domain_token()),
783            _ => None,
784        };
785
786        self.zxio
787            .setsockopt(level as i32, optname as i32, &optval, access_token)
788            .map_err(|status| from_status_like_fdio!(status))?
789            .map_err(|out_code| errno_from_zxio_code!(out_code))
790    }
791
792    fn getsockopt(
793        &self,
794        _socket: &Socket,
795        _current_task: &CurrentTask,
796        level: u32,
797        optname: u32,
798        optlen: u32,
799    ) -> Result<Vec<u8>, Errno> {
800        match (level, optname) {
801            // SO_MARK is specialized because linux socket marks are not compatible
802            // with fuchsia socket marks. We need to get the socket mark from the
803            // `ZXIO_SOCKET_MARK_SO_MARK` domain.
804            (SOL_SOCKET, SO_MARK) => {
805                let mut optval: [u8; size_of::<zxio_socket_mark>()] =
806                    zerocopy::try_transmute!(zxio_socket_mark {
807                        is_present: false,
808                        domain: fidl_fuchsia_net::MARK_DOMAIN_SO_MARK as u8,
809                        value: 0,
810                        ..Default::default()
811                    })
812                    .expect("invalid bit pattern");
813                // Retrieves the `zxio_socket_mark` from the domain.
814                let optlen = self
815                    .zxio
816                    .getsockopt_slice(level, SO_FUCHSIA_MARK, &mut optval)
817                    .map_err(|status| from_status_like_fdio!(status))?
818                    .map_err(|out_code| errno_from_zxio_code!(out_code))?;
819                if optlen as usize != size_of::<zxio_socket_mark>() {
820                    return error!(EINVAL);
821                }
822                let socket_mark: zxio_socket_mark =
823                    zerocopy::try_transmute!(optval).map_err(|_validity_err| errno!(EINVAL))?;
824                // Translate to a linux mark, the default value is 0.
825                let mark = if socket_mark.is_present { socket_mark.value } else { 0 };
826                let mut result = vec![0; 4];
827                byteorder::NativeEndian::write_u32(&mut result, mark);
828                Ok(result)
829            }
830            (SOL_SOCKET, SO_COOKIE) => {
831                self.get_socket_cookie().map(|cookie| cookie.as_bytes().to_owned())
832            }
833            (SOL_IP, IP_MULTICAST_ALL) => {
834                track_stub!(TODO("https://fxbug.dev/404596095"), "SOL_IP.IP_MULTICAST_ALL");
835                let mut result = vec![0; 4];
836                byteorder::NativeEndian::write_u32(&mut result, 0);
837                Ok(result)
838            }
839            _ => self
840                .zxio
841                .getsockopt(level, optname, optlen)
842                .map_err(|status| from_status_like_fdio!(status))?
843                .map_err(|out_code| errno_from_zxio_code!(out_code)),
844        }
845    }
846
847    fn to_handle(
848        &self,
849        _socket: &Socket,
850        _current_task: &CurrentTask,
851    ) -> Result<Option<zx::NullableHandle>, Errno> {
852        self.zxio
853            .deep_clone()
854            .and_then(Zxio::release)
855            .map(Some)
856            .map_err(|status| from_status_like_fdio!(status))
857    }
858
859    fn ioctl(
860        &self,
861        socket: &Socket,
862        _file: &FileObject,
863        current_task: &CurrentTask,
864        request: u32,
865        arg: SyscallArg,
866    ) -> Result<SyscallResult, Errno> {
867        let user_addr = UserAddress::from(arg);
868        match request {
869            FIONREAD if socket.socket_type == SocketType::Stream => {
870                let available = self
871                    .zxio
872                    .get_read_buffer_available()
873                    .map_err(|status| from_status_like_fdio!(status))?;
874                let available: i32 = available.try_into().map_err(|_| errno!(EINVAL))?;
875                current_task.write_object(UserRef::<i32>::new(user_addr), &available)?;
876                Ok(SUCCESS)
877            }
878            _ => error!(ENOTTY),
879        }
880    }
881}
882
883pub use tokens_store::SocketTokensStore;
884type SocketTokenResolver = tokens_store::SocketTokenResolver<Kernel>;
885
886mod tokens_store {
887    use crate::task::Kernel;
888    use derivative::Derivative;
889    use fuchsia_async as fasync;
890    use fuchsia_rcu::RcuDroppable;
891    use starnix_rcu::RcuHashMap;
892    use starnix_rcu::rcu_hash_map::Entry;
893    use starnix_uapi::uid_t;
894    use std::sync::{Arc, OnceLock, Weak};
895
896    /// Trait for the `Kernel` functionality used in `SocketTokensStore`. Mocked
897    /// in tests.
898    pub trait SocketTokenStoreHost: Sized + Sync + Send + 'static {
899        fn get_socket_tokens_store(&self) -> &SocketTokensStore<Self>;
900        fn spawn_future(&self, future: impl AsyncFnOnce() -> () + Send + 'static);
901    }
902
903    impl SocketTokenStoreHost for Kernel {
904        fn get_socket_tokens_store(&self) -> &SocketTokensStore<Self> {
905            &self.socket_tokens_store
906        }
907        fn spawn_future(&self, future: impl AsyncFnOnce() -> () + Send + 'static) {
908            self.kthreads.spawn_future(future, "socket_accept")
909        }
910    }
911
912    // Collection of tokens associated with a UID.
913    #[derive(Debug)]
914    struct TokenCollection {
915        // Sharing domain token. Allocated lazily on first use.
916        sharing_domain_token: OnceLock<zx::Event>,
917    }
918
919    impl TokenCollection {
920        fn new() -> Arc<Self> {
921            Arc::new(Self { sharing_domain_token: OnceLock::new() })
922        }
923
924        /// Returns the number of handles for the tokens held beside this collection itself.
925        fn get_handles_ref_count(&self) -> u32 {
926            self.sharing_domain_token
927                .get()
928                .map(|token| {
929                    token.count_info().expect("ZX_INFO_HANDLE_COUNT query failed").handle_count - 1
930                })
931                .unwrap_or(0)
932        }
933    }
934
935    impl TokenCollection {
936        fn get_sharing_domain_token(&self) -> zx::NullableHandle {
937            self.sharing_domain_token
938                .get_or_init(|| zx::Event::create())
939                .duplicate_handle(zx::Rights::TRANSFER)
940                .expect("Failed to duplicate handle")
941                .into()
942        }
943    }
944
945    #[derive(Debug, Clone, Copy)]
946    enum UidEntryState {
947        // The entry is unused and can be removed.
948        Unused,
949
950        // The entry is being referenced by sockets.
951        Used,
952
953        // The entry is not referenced by sockets, but the sharing domains socket
954        // is still referenced by netstack.
955        Linger,
956    }
957
958    // Information stored for each UID in `SocketTokensStore`. Each entry is kept
959    // only as long as there may be sockets associated with this UID.
960    #[derive(Derivative)]
961    #[derivative(Clone(bound = ""))]
962    struct UidEntry<H: SocketTokenStoreHost> {
963        tokens: Arc<TokenCollection>,
964
965        // Weak reference to the resolver associated with this UID.
966        weak_resolver: Weak<SocketTokenResolver<H>>,
967
968        // Whether the cleanup task is running.
969        cleanup_task_running: bool,
970    }
971
972    // SAFETY: UidEntry does not have Drop side effects.
973    unsafe impl<H: SocketTokenStoreHost> RcuDroppable for UidEntry<H> {}
974
975    impl<H: SocketTokenStoreHost> UidEntry<H> {
976        fn new() -> Self {
977            Self {
978                tokens: TokenCollection::new(),
979                weak_resolver: Weak::new(),
980                cleanup_task_running: false,
981            }
982        }
983
984        fn get_state(&self) -> UidEntryState {
985            match (self.tokens.get_handles_ref_count(), self.weak_resolver.strong_count()) {
986                (0, 0) => UidEntryState::Unused,
987                (_, 0) => UidEntryState::Linger,
988                _ => UidEntryState::Used,
989            }
990        }
991    }
992
993    #[derive(Derivative)]
994    #[derivative(Default(bound = ""))]
995    pub struct SocketTokensStore<H: SocketTokenStoreHost = Kernel> {
996        map: RcuHashMap<uid_t, UidEntry<H>>,
997    }
998
999    /// Delay between cleanup attempts.
1000    const CLEANUP_RETRY_DELAY: zx::MonotonicDuration = zx::MonotonicDuration::from_minutes(1);
1001
1002    impl<H: SocketTokenStoreHost> SocketTokensStore<H> {
1003        pub(super) fn get_token_resolver(
1004            &self,
1005            host: &Arc<H>,
1006            uid: uid_t,
1007        ) -> Arc<SocketTokenResolver<H>> {
1008            let mut guard = self.map.lock();
1009            let mut entry = guard.entry(uid).or_insert_with(|| UidEntry::new());
1010
1011            match entry.get().weak_resolver.upgrade() {
1012                Some(resolver) => resolver,
1013                None => {
1014                    let resolver = SocketTokenResolver::new(entry.get().tokens, host, uid);
1015                    let mut new_entry = entry.get();
1016                    new_entry.weak_resolver = Arc::downgrade(&resolver);
1017                    entry.insert(new_entry);
1018                    resolver
1019                }
1020            }
1021        }
1022
1023        fn on_resolver_dropped(&self, host: &Arc<H>, uid: uid_t) {
1024            {
1025                let mut guard = self.map.lock();
1026                let Entry::Occupied(mut entry) = guard.entry(uid) else {
1027                    // The entry may be missing if another thread has created and removed another
1028                    // resolver for this UID.
1029                    return;
1030                };
1031                if entry.get().cleanup_task_running {
1032                    return;
1033                }
1034                match entry.get().get_state() {
1035                    UidEntryState::Unused => {
1036                        entry.remove();
1037                        return;
1038                    }
1039                    UidEntryState::Used => return,
1040                    UidEntryState::Linger => (),
1041                }
1042
1043                let mut new_entry = entry.get();
1044                new_entry.cleanup_task_running = true;
1045                entry.insert(new_entry);
1046            }
1047
1048            // Start cleanup task.
1049            let weak_host = Arc::downgrade(host);
1050            host.spawn_future(async move || {
1051                loop {
1052                    // Wait for a bit and then retry cleanup.
1053                    fasync::Timer::new(fasync::MonotonicInstant::after(CLEANUP_RETRY_DELAY)).await;
1054
1055                    let Some(host) = weak_host.upgrade() else {
1056                        return;
1057                    };
1058                    let mut guard = host.get_socket_tokens_store().map.lock();
1059                    let Entry::Occupied(mut entry) = guard.entry(uid) else {
1060                        return;
1061                    };
1062                    match entry.get().get_state() {
1063                        UidEntryState::Unused => {
1064                            // We can remove the entry now.
1065                            entry.remove();
1066                            return;
1067                        }
1068                        UidEntryState::Used => {
1069                            // Quit cleanup task. It will be restarted later in
1070                            // `on_resolver_dropped()`.
1071                            let mut new_entry = entry.get();
1072                            new_entry.cleanup_task_running = false;
1073                            entry.insert(new_entry);
1074                            return;
1075                        }
1076                        UidEntryState::Linger => (),
1077                    }
1078                }
1079            });
1080        }
1081    }
1082
1083    // Resolver for socket tokens. This type essentially acts as a proxy for
1084    // `TokenCollection` that also notifies `SocketTokensStore` when it is dropped.
1085    pub struct SocketTokenResolver<H: SocketTokenStoreHost> {
1086        tokens: Arc<TokenCollection>,
1087
1088        // Used in `Drop` implementation to cleanup the entry in
1089        // `SocketTokensStore`.
1090        host: Weak<H>,
1091        uid: uid_t,
1092    }
1093
1094    impl<H: SocketTokenStoreHost> SocketTokenResolver<H> {
1095        fn new(tokens: Arc<TokenCollection>, host: &Arc<H>, uid: uid_t) -> Arc<Self> {
1096            Arc::new(Self { tokens, host: Arc::downgrade(host), uid })
1097        }
1098
1099        pub fn get_sharing_domain_token(&self) -> zx::NullableHandle {
1100            self.tokens.get_sharing_domain_token()
1101        }
1102    }
1103
1104    impl<H: SocketTokenStoreHost> Drop for SocketTokenResolver<H> {
1105        fn drop(&mut self) {
1106            if let Some(host) = self.host.upgrade() {
1107                host.get_socket_tokens_store().on_resolver_dropped(&host, self.uid);
1108            }
1109        }
1110    }
1111
1112    #[cfg(test)]
1113    mod tests {
1114        use super::*;
1115        use fuchsia_async::TestExecutor;
1116        use std::pin::pin;
1117        use test_case::test_matrix;
1118        use zx::MonotonicDuration;
1119
1120        struct TestSocketTokenStoreHost {
1121            socket_tokens_store: SocketTokensStore<TestSocketTokenStoreHost>,
1122        }
1123        impl TestSocketTokenStoreHost {
1124            fn new() -> Arc<Self> {
1125                Arc::new(Self { socket_tokens_store: SocketTokensStore::default() })
1126            }
1127        }
1128
1129        impl SocketTokenStoreHost for TestSocketTokenStoreHost {
1130            fn get_socket_tokens_store(&self) -> &SocketTokensStore<Self> {
1131                &self.socket_tokens_store
1132            }
1133            fn spawn_future(&self, future: impl AsyncFnOnce() -> () + Send + 'static) {
1134                fasync::Task::spawn(async move { fasync::Task::local(future()).await }).detach();
1135            }
1136        }
1137
1138        fn advance_time(executor: &mut TestExecutor, d: MonotonicDuration) {
1139            let r = executor.run_until_stalled(&mut pin!(TestExecutor::advance_to(
1140                fasync::MonotonicInstant::after(d)
1141            )));
1142            assert!(r.is_ready());
1143        }
1144
1145        const UID: uid_t = 100;
1146
1147        #[::fuchsia::test]
1148        fn test_socket_tokens_store_base() {
1149            let host = TestSocketTokenStoreHost::new();
1150            let store = &host.socket_tokens_store;
1151            let token_resolver = store.get_token_resolver(&host, UID);
1152            assert!(store.map.lock().contains_key(&UID));
1153            drop(token_resolver);
1154            assert!(!store.map.lock().contains_key(&UID));
1155        }
1156
1157        #[::fuchsia::test]
1158        fn test_socket_tokens_store_drop_handle_first() {
1159            let host = TestSocketTokenStoreHost::new();
1160            let store = &host.socket_tokens_store;
1161            let token_resolver = store.get_token_resolver(&host, UID);
1162            assert!(store.map.lock().contains_key(&UID));
1163
1164            let token = token_resolver.get_sharing_domain_token();
1165            drop(token);
1166            drop(token_resolver);
1167
1168            assert!(!store.map.lock().contains_key(&UID));
1169        }
1170
1171        #[::fuchsia::test]
1172        fn test_socket_tokens_store_linger() {
1173            let mut executor = TestExecutor::new_with_fake_time();
1174            let host = TestSocketTokenStoreHost::new();
1175            let store = &host.socket_tokens_store;
1176            let token_resolver = store.get_token_resolver(&host, UID);
1177            let token = token_resolver.get_sharing_domain_token();
1178            assert!(store.map.lock().contains_key(&UID));
1179            drop(token_resolver);
1180
1181            // The entry should not be dropped since we still hold the token
1182            assert!(store.map.lock().contains_key(&UID));
1183            advance_time(&mut executor, CLEANUP_RETRY_DELAY * 2);
1184            assert!(store.map.lock().contains_key(&UID));
1185
1186            // The entry should be dropped shortly after the token is dropped.
1187            drop(token);
1188            advance_time(&mut executor, CLEANUP_RETRY_DELAY);
1189            assert!(!store.map.lock().contains_key(&UID));
1190        }
1191
1192        #[test_matrix(
1193            [CLEANUP_RETRY_DELAY / 2,
1194            CLEANUP_RETRY_DELAY,
1195            CLEANUP_RETRY_DELAY * 3 / 2],
1196            [CLEANUP_RETRY_DELAY / 2,
1197            CLEANUP_RETRY_DELAY,
1198            CLEANUP_RETRY_DELAY * 3 / 2],
1199            [true, false]
1200        )]
1201        #[::fuchsia::test]
1202        fn test_socket_tokens_store_recreate(
1203            delay1: MonotonicDuration,
1204            delay2: MonotonicDuration,
1205            drop_tokens_first: bool,
1206        ) {
1207            let mut executor = TestExecutor::new_with_fake_time();
1208            let host = TestSocketTokenStoreHost::new();
1209            let store = &host.socket_tokens_store;
1210            let token_resolver = store.get_token_resolver(&host, UID);
1211            let token1 = token_resolver.get_sharing_domain_token();
1212            drop(token_resolver);
1213
1214            // The entry should not be dropped since we still hold the token
1215            advance_time(&mut executor, delay1);
1216            assert!(store.map.lock().contains_key(&UID));
1217
1218            // Create another resolver. It should reuse the same token.
1219            let token_resolver = store.get_token_resolver(&host, UID);
1220            let token2 = token_resolver.get_sharing_domain_token();
1221            assert!(token1.koid() == token2.koid());
1222
1223            // Token should not be dropped while we have a TokenResolver.
1224            advance_time(&mut executor, delay2);
1225            assert!(store.map.lock().contains_key(&UID));
1226
1227            if drop_tokens_first {
1228                drop(token1);
1229                drop(token2);
1230                drop(token_resolver);
1231            } else {
1232                drop(token_resolver);
1233                drop(token1);
1234                drop(token2);
1235            }
1236
1237            // The timer is expected to be rescheduled if it ran between `delay1` and
1238            // `delay1 + delay2`.
1239            let timer_rescheduled = (delay1.into_seconds() / CLEANUP_RETRY_DELAY.into_seconds())
1240                != ((delay1 + delay2).into_seconds() / CLEANUP_RETRY_DELAY.into_seconds());
1241
1242            if timer_rescheduled && drop_tokens_first {
1243                // The entry should be dropped since we dropped the tokens first.
1244                assert!(!store.map.lock().contains_key(&UID));
1245            } else {
1246                let expected_cleanup_delay = if timer_rescheduled {
1247                    CLEANUP_RETRY_DELAY
1248                } else {
1249                    CLEANUP_RETRY_DELAY
1250                        - MonotonicDuration::from_seconds(
1251                            (delay1 + delay2).into_seconds() % CLEANUP_RETRY_DELAY.into_seconds(),
1252                        )
1253                };
1254
1255                // The tokens should be dropped exactly after `expected_cleanup_delay`.
1256                let one_second = MonotonicDuration::from_seconds(1);
1257                advance_time(&mut executor, expected_cleanup_delay - one_second);
1258                assert!(store.map.lock().contains_key(&UID));
1259                advance_time(&mut executor, one_second);
1260                assert!(!store.map.lock().contains_key(&UID));
1261            }
1262        }
1263    }
1264}
1265
1266// Check that values that are passed to and from ZXIO have the same meaning.
1267const_assert_eq!(syncio::zxio::AF_UNSPEC, uapi::AF_UNSPEC as u32);
1268const_assert_eq!(syncio::zxio::AF_UNIX, uapi::AF_UNIX as u32);
1269const_assert_eq!(syncio::zxio::AF_INET, uapi::AF_INET as u32);
1270const_assert_eq!(syncio::zxio::AF_INET6, uapi::AF_INET6 as u32);
1271const_assert_eq!(syncio::zxio::AF_NETLINK, uapi::AF_NETLINK as u32);
1272const_assert_eq!(syncio::zxio::AF_PACKET, uapi::AF_PACKET as u32);
1273const_assert_eq!(syncio::zxio::AF_VSOCK, uapi::AF_VSOCK as u32);
1274
1275const_assert_eq!(syncio::zxio::SO_DEBUG, uapi::SO_DEBUG);
1276const_assert_eq!(syncio::zxio::SO_REUSEADDR, uapi::SO_REUSEADDR);
1277const_assert_eq!(syncio::zxio::SO_TYPE, uapi::SO_TYPE);
1278const_assert_eq!(syncio::zxio::SO_ERROR, uapi::SO_ERROR);
1279const_assert_eq!(syncio::zxio::SO_DONTROUTE, uapi::SO_DONTROUTE);
1280const_assert_eq!(syncio::zxio::SO_BROADCAST, uapi::SO_BROADCAST);
1281const_assert_eq!(syncio::zxio::SO_SNDBUF, uapi::SO_SNDBUF);
1282const_assert_eq!(syncio::zxio::SO_RCVBUF, uapi::SO_RCVBUF);
1283const_assert_eq!(syncio::zxio::SO_KEEPALIVE, uapi::SO_KEEPALIVE);
1284const_assert_eq!(syncio::zxio::SO_OOBINLINE, uapi::SO_OOBINLINE);
1285const_assert_eq!(syncio::zxio::SO_NO_CHECK, uapi::SO_NO_CHECK);
1286const_assert_eq!(syncio::zxio::SO_PRIORITY, uapi::SO_PRIORITY);
1287const_assert_eq!(syncio::zxio::SO_LINGER, uapi::SO_LINGER);
1288const_assert_eq!(syncio::zxio::SO_BSDCOMPAT, uapi::SO_BSDCOMPAT);
1289const_assert_eq!(syncio::zxio::SO_REUSEPORT, uapi::SO_REUSEPORT);
1290const_assert_eq!(syncio::zxio::SO_PASSCRED, uapi::SO_PASSCRED);
1291const_assert_eq!(syncio::zxio::SO_PEERCRED, uapi::SO_PEERCRED);
1292const_assert_eq!(syncio::zxio::SO_RCVLOWAT, uapi::SO_RCVLOWAT);
1293const_assert_eq!(syncio::zxio::SO_SNDLOWAT, uapi::SO_SNDLOWAT);
1294const_assert_eq!(syncio::zxio::SO_ACCEPTCONN, uapi::SO_ACCEPTCONN);
1295const_assert_eq!(syncio::zxio::SO_PEERSEC, uapi::SO_PEERSEC);
1296const_assert_eq!(syncio::zxio::SO_SNDBUFFORCE, uapi::SO_SNDBUFFORCE);
1297const_assert_eq!(syncio::zxio::SO_RCVBUFFORCE, uapi::SO_RCVBUFFORCE);
1298const_assert_eq!(syncio::zxio::SO_PROTOCOL, uapi::SO_PROTOCOL);
1299const_assert_eq!(syncio::zxio::SO_DOMAIN, uapi::SO_DOMAIN);
1300const_assert_eq!(syncio::zxio::SO_RCVTIMEO, uapi::SO_RCVTIMEO);
1301const_assert_eq!(syncio::zxio::SO_SNDTIMEO, uapi::SO_SNDTIMEO);
1302const_assert_eq!(syncio::zxio::SO_TIMESTAMP, uapi::SO_TIMESTAMP);
1303const_assert_eq!(syncio::zxio::SO_TIMESTAMPNS, uapi::SO_TIMESTAMPNS);
1304const_assert_eq!(syncio::zxio::SO_TIMESTAMPING, uapi::SO_TIMESTAMPING);
1305const_assert_eq!(syncio::zxio::SO_SECURITY_AUTHENTICATION, uapi::SO_SECURITY_AUTHENTICATION);
1306const_assert_eq!(
1307    syncio::zxio::SO_SECURITY_ENCRYPTION_TRANSPORT,
1308    uapi::SO_SECURITY_ENCRYPTION_TRANSPORT
1309);
1310const_assert_eq!(
1311    syncio::zxio::SO_SECURITY_ENCRYPTION_NETWORK,
1312    uapi::SO_SECURITY_ENCRYPTION_NETWORK
1313);
1314const_assert_eq!(syncio::zxio::SO_BINDTODEVICE, uapi::SO_BINDTODEVICE);
1315const_assert_eq!(syncio::zxio::SO_ATTACH_FILTER, uapi::SO_ATTACH_FILTER);
1316const_assert_eq!(syncio::zxio::SO_DETACH_FILTER, uapi::SO_DETACH_FILTER);
1317const_assert_eq!(syncio::zxio::SO_GET_FILTER, uapi::SO_GET_FILTER);
1318const_assert_eq!(syncio::zxio::SO_PEERNAME, uapi::SO_PEERNAME);
1319const_assert_eq!(syncio::zxio::SO_PASSSEC, uapi::SO_PASSSEC);
1320const_assert_eq!(syncio::zxio::SO_MARK, uapi::SO_MARK);
1321const_assert_eq!(syncio::zxio::SO_RXQ_OVFL, uapi::SO_RXQ_OVFL);
1322const_assert_eq!(syncio::zxio::SO_WIFI_STATUS, uapi::SO_WIFI_STATUS);
1323const_assert_eq!(syncio::zxio::SO_PEEK_OFF, uapi::SO_PEEK_OFF);
1324const_assert_eq!(syncio::zxio::SO_NOFCS, uapi::SO_NOFCS);
1325const_assert_eq!(syncio::zxio::SO_LOCK_FILTER, uapi::SO_LOCK_FILTER);
1326const_assert_eq!(syncio::zxio::SO_SELECT_ERR_QUEUE, uapi::SO_SELECT_ERR_QUEUE);
1327const_assert_eq!(syncio::zxio::SO_BUSY_POLL, uapi::SO_BUSY_POLL);
1328const_assert_eq!(syncio::zxio::SO_MAX_PACING_RATE, uapi::SO_MAX_PACING_RATE);
1329const_assert_eq!(syncio::zxio::SO_BPF_EXTENSIONS, uapi::SO_BPF_EXTENSIONS);
1330const_assert_eq!(syncio::zxio::SO_INCOMING_CPU, uapi::SO_INCOMING_CPU);
1331const_assert_eq!(syncio::zxio::SO_ATTACH_BPF, uapi::SO_ATTACH_BPF);
1332const_assert_eq!(syncio::zxio::SO_DETACH_BPF, uapi::SO_DETACH_BPF);
1333const_assert_eq!(syncio::zxio::SO_ATTACH_REUSEPORT_CBPF, uapi::SO_ATTACH_REUSEPORT_CBPF);
1334const_assert_eq!(syncio::zxio::SO_ATTACH_REUSEPORT_EBPF, uapi::SO_ATTACH_REUSEPORT_EBPF);
1335const_assert_eq!(syncio::zxio::SO_CNX_ADVICE, uapi::SO_CNX_ADVICE);
1336const_assert_eq!(syncio::zxio::SO_MEMINFO, uapi::SO_MEMINFO);
1337const_assert_eq!(syncio::zxio::SO_INCOMING_NAPI_ID, uapi::SO_INCOMING_NAPI_ID);
1338const_assert_eq!(syncio::zxio::SO_COOKIE, uapi::SO_COOKIE);
1339const_assert_eq!(syncio::zxio::SO_PEERGROUPS, uapi::SO_PEERGROUPS);
1340const_assert_eq!(syncio::zxio::SO_ZEROCOPY, uapi::SO_ZEROCOPY);
1341const_assert_eq!(syncio::zxio::SO_TXTIME, uapi::SO_TXTIME);
1342const_assert_eq!(syncio::zxio::SO_BINDTOIFINDEX, uapi::SO_BINDTOIFINDEX);
1343const_assert_eq!(syncio::zxio::SO_DETACH_REUSEPORT_BPF, uapi::SO_DETACH_REUSEPORT_BPF);
1344const_assert_eq!(syncio::zxio::SO_ORIGINAL_DST, uapi::SO_ORIGINAL_DST);
1345
1346const_assert_eq!(syncio::zxio::MSG_WAITALL, uapi::MSG_WAITALL);
1347const_assert_eq!(syncio::zxio::MSG_PEEK, uapi::MSG_PEEK);
1348const_assert_eq!(syncio::zxio::MSG_DONTROUTE, uapi::MSG_DONTROUTE);
1349const_assert_eq!(syncio::zxio::MSG_CTRUNC, uapi::MSG_CTRUNC);
1350const_assert_eq!(syncio::zxio::MSG_PROXY, uapi::MSG_PROXY);
1351const_assert_eq!(syncio::zxio::MSG_TRUNC, uapi::MSG_TRUNC);
1352const_assert_eq!(syncio::zxio::MSG_DONTWAIT, uapi::MSG_DONTWAIT);
1353const_assert_eq!(syncio::zxio::MSG_EOR, uapi::MSG_EOR);
1354const_assert_eq!(syncio::zxio::MSG_WAITALL, uapi::MSG_WAITALL);
1355const_assert_eq!(syncio::zxio::MSG_FIN, uapi::MSG_FIN);
1356const_assert_eq!(syncio::zxio::MSG_SYN, uapi::MSG_SYN);
1357const_assert_eq!(syncio::zxio::MSG_CONFIRM, uapi::MSG_CONFIRM);
1358const_assert_eq!(syncio::zxio::MSG_RST, uapi::MSG_RST);
1359const_assert_eq!(syncio::zxio::MSG_ERRQUEUE, uapi::MSG_ERRQUEUE);
1360const_assert_eq!(syncio::zxio::MSG_NOSIGNAL, uapi::MSG_NOSIGNAL);
1361const_assert_eq!(syncio::zxio::MSG_MORE, uapi::MSG_MORE);
1362const_assert_eq!(syncio::zxio::MSG_WAITFORONE, uapi::MSG_WAITFORONE);
1363const_assert_eq!(syncio::zxio::MSG_BATCH, uapi::MSG_BATCH);
1364const_assert_eq!(syncio::zxio::MSG_FASTOPEN, uapi::MSG_FASTOPEN);
1365const_assert_eq!(syncio::zxio::MSG_CMSG_CLOEXEC, uapi::MSG_CMSG_CLOEXEC);
1366
1367const_assert_eq!(syncio::zxio::IP_TOS, uapi::IP_TOS);
1368const_assert_eq!(syncio::zxio::IP_TTL, uapi::IP_TTL);
1369const_assert_eq!(syncio::zxio::IP_HDRINCL, uapi::IP_HDRINCL);
1370const_assert_eq!(syncio::zxio::IP_OPTIONS, uapi::IP_OPTIONS);
1371const_assert_eq!(syncio::zxio::IP_ROUTER_ALERT, uapi::IP_ROUTER_ALERT);
1372const_assert_eq!(syncio::zxio::IP_RECVOPTS, uapi::IP_RECVOPTS);
1373const_assert_eq!(syncio::zxio::IP_RETOPTS, uapi::IP_RETOPTS);
1374const_assert_eq!(syncio::zxio::IP_PKTINFO, uapi::IP_PKTINFO);
1375const_assert_eq!(syncio::zxio::IP_PKTOPTIONS, uapi::IP_PKTOPTIONS);
1376const_assert_eq!(syncio::zxio::IP_MTU_DISCOVER, uapi::IP_MTU_DISCOVER);
1377const_assert_eq!(syncio::zxio::IP_RECVERR, uapi::IP_RECVERR);
1378const_assert_eq!(syncio::zxio::IP_RECVTTL, uapi::IP_RECVTTL);
1379const_assert_eq!(syncio::zxio::IP_RECVTOS, uapi::IP_RECVTOS);
1380const_assert_eq!(syncio::zxio::IP_MTU, uapi::IP_MTU);
1381const_assert_eq!(syncio::zxio::IP_FREEBIND, uapi::IP_FREEBIND);
1382const_assert_eq!(syncio::zxio::IP_IPSEC_POLICY, uapi::IP_IPSEC_POLICY);
1383const_assert_eq!(syncio::zxio::IP_XFRM_POLICY, uapi::IP_XFRM_POLICY);
1384const_assert_eq!(syncio::zxio::IP_PASSSEC, uapi::IP_PASSSEC);
1385const_assert_eq!(syncio::zxio::IP_TRANSPARENT, uapi::IP_TRANSPARENT);
1386const_assert_eq!(syncio::zxio::IP_ORIGDSTADDR, uapi::IP_ORIGDSTADDR);
1387const_assert_eq!(syncio::zxio::IP_RECVORIGDSTADDR, uapi::IP_RECVORIGDSTADDR);
1388const_assert_eq!(syncio::zxio::IP_MINTTL, uapi::IP_MINTTL);
1389const_assert_eq!(syncio::zxio::IP_NODEFRAG, uapi::IP_NODEFRAG);
1390const_assert_eq!(syncio::zxio::IP_CHECKSUM, uapi::IP_CHECKSUM);
1391const_assert_eq!(syncio::zxio::IP_BIND_ADDRESS_NO_PORT, uapi::IP_BIND_ADDRESS_NO_PORT);
1392const_assert_eq!(syncio::zxio::IP_MULTICAST_IF, uapi::IP_MULTICAST_IF);
1393const_assert_eq!(syncio::zxio::IP_MULTICAST_TTL, uapi::IP_MULTICAST_TTL);
1394const_assert_eq!(syncio::zxio::IP_MULTICAST_LOOP, uapi::IP_MULTICAST_LOOP);
1395const_assert_eq!(syncio::zxio::IP_ADD_MEMBERSHIP, uapi::IP_ADD_MEMBERSHIP);
1396const_assert_eq!(syncio::zxio::IP_DROP_MEMBERSHIP, uapi::IP_DROP_MEMBERSHIP);
1397const_assert_eq!(syncio::zxio::IP_UNBLOCK_SOURCE, uapi::IP_UNBLOCK_SOURCE);
1398const_assert_eq!(syncio::zxio::IP_BLOCK_SOURCE, uapi::IP_BLOCK_SOURCE);
1399const_assert_eq!(syncio::zxio::IP_ADD_SOURCE_MEMBERSHIP, uapi::IP_ADD_SOURCE_MEMBERSHIP);
1400const_assert_eq!(syncio::zxio::IP_DROP_SOURCE_MEMBERSHIP, uapi::IP_DROP_SOURCE_MEMBERSHIP);
1401const_assert_eq!(syncio::zxio::IP_MSFILTER, uapi::IP_MSFILTER);
1402const_assert_eq!(syncio::zxio::IP_MULTICAST_ALL, uapi::IP_MULTICAST_ALL);
1403const_assert_eq!(syncio::zxio::IP_UNICAST_IF, uapi::IP_UNICAST_IF);
1404const_assert_eq!(syncio::zxio::IP_RECVRETOPTS, uapi::IP_RECVRETOPTS);
1405const_assert_eq!(syncio::zxio::IP_PMTUDISC_DONT, uapi::IP_PMTUDISC_DONT);
1406const_assert_eq!(syncio::zxio::IP_PMTUDISC_WANT, uapi::IP_PMTUDISC_WANT);
1407const_assert_eq!(syncio::zxio::IP_PMTUDISC_DO, uapi::IP_PMTUDISC_DO);
1408const_assert_eq!(syncio::zxio::IP_PMTUDISC_PROBE, uapi::IP_PMTUDISC_PROBE);
1409const_assert_eq!(syncio::zxio::IP_PMTUDISC_INTERFACE, uapi::IP_PMTUDISC_INTERFACE);
1410const_assert_eq!(syncio::zxio::IP_PMTUDISC_OMIT, uapi::IP_PMTUDISC_OMIT);
1411const_assert_eq!(syncio::zxio::IP_DEFAULT_MULTICAST_TTL, uapi::IP_DEFAULT_MULTICAST_TTL);
1412const_assert_eq!(syncio::zxio::IP_DEFAULT_MULTICAST_LOOP, uapi::IP_DEFAULT_MULTICAST_LOOP);
1413
1414const_assert_eq!(syncio::zxio::IPV6_ADDRFORM, uapi::IPV6_ADDRFORM);
1415const_assert_eq!(syncio::zxio::IPV6_2292PKTINFO, uapi::IPV6_2292PKTINFO);
1416const_assert_eq!(syncio::zxio::IPV6_2292HOPOPTS, uapi::IPV6_2292HOPOPTS);
1417const_assert_eq!(syncio::zxio::IPV6_2292DSTOPTS, uapi::IPV6_2292DSTOPTS);
1418const_assert_eq!(syncio::zxio::IPV6_2292RTHDR, uapi::IPV6_2292RTHDR);
1419const_assert_eq!(syncio::zxio::IPV6_2292PKTOPTIONS, uapi::IPV6_2292PKTOPTIONS);
1420const_assert_eq!(syncio::zxio::IPV6_CHECKSUM, uapi::IPV6_CHECKSUM);
1421const_assert_eq!(syncio::zxio::IPV6_2292HOPLIMIT, uapi::IPV6_2292HOPLIMIT);
1422const_assert_eq!(syncio::zxio::IPV6_NEXTHOP, uapi::IPV6_NEXTHOP);
1423const_assert_eq!(syncio::zxio::IPV6_AUTHHDR, uapi::IPV6_AUTHHDR);
1424const_assert_eq!(syncio::zxio::IPV6_UNICAST_HOPS, uapi::IPV6_UNICAST_HOPS);
1425const_assert_eq!(syncio::zxio::IPV6_MULTICAST_IF, uapi::IPV6_MULTICAST_IF);
1426const_assert_eq!(syncio::zxio::IPV6_MULTICAST_HOPS, uapi::IPV6_MULTICAST_HOPS);
1427const_assert_eq!(syncio::zxio::IPV6_MULTICAST_LOOP, uapi::IPV6_MULTICAST_LOOP);
1428const_assert_eq!(syncio::zxio::IPV6_ROUTER_ALERT, uapi::IPV6_ROUTER_ALERT);
1429const_assert_eq!(syncio::zxio::IPV6_MTU_DISCOVER, uapi::IPV6_MTU_DISCOVER);
1430const_assert_eq!(syncio::zxio::IPV6_MTU, uapi::IPV6_MTU);
1431const_assert_eq!(syncio::zxio::IPV6_RECVERR, uapi::IPV6_RECVERR);
1432const_assert_eq!(syncio::zxio::IPV6_V6ONLY, uapi::IPV6_V6ONLY);
1433const_assert_eq!(syncio::zxio::IPV6_JOIN_ANYCAST, uapi::IPV6_JOIN_ANYCAST);
1434const_assert_eq!(syncio::zxio::IPV6_LEAVE_ANYCAST, uapi::IPV6_LEAVE_ANYCAST);
1435const_assert_eq!(syncio::zxio::IPV6_IPSEC_POLICY, uapi::IPV6_IPSEC_POLICY);
1436const_assert_eq!(syncio::zxio::IPV6_XFRM_POLICY, uapi::IPV6_XFRM_POLICY);
1437const_assert_eq!(syncio::zxio::IPV6_HDRINCL, uapi::IPV6_HDRINCL);
1438const_assert_eq!(syncio::zxio::IPV6_RECVPKTINFO, uapi::IPV6_RECVPKTINFO);
1439const_assert_eq!(syncio::zxio::IPV6_PKTINFO, uapi::IPV6_PKTINFO);
1440const_assert_eq!(syncio::zxio::IPV6_RECVHOPLIMIT, uapi::IPV6_RECVHOPLIMIT);
1441const_assert_eq!(syncio::zxio::IPV6_HOPLIMIT, uapi::IPV6_HOPLIMIT);
1442const_assert_eq!(syncio::zxio::IPV6_RECVHOPOPTS, uapi::IPV6_RECVHOPOPTS);
1443const_assert_eq!(syncio::zxio::IPV6_HOPOPTS, uapi::IPV6_HOPOPTS);
1444const_assert_eq!(syncio::zxio::IPV6_RTHDRDSTOPTS, uapi::IPV6_RTHDRDSTOPTS);
1445const_assert_eq!(syncio::zxio::IPV6_RECVRTHDR, uapi::IPV6_RECVRTHDR);
1446const_assert_eq!(syncio::zxio::IPV6_RTHDR, uapi::IPV6_RTHDR);
1447const_assert_eq!(syncio::zxio::IPV6_RECVDSTOPTS, uapi::IPV6_RECVDSTOPTS);
1448const_assert_eq!(syncio::zxio::IPV6_DSTOPTS, uapi::IPV6_DSTOPTS);
1449const_assert_eq!(syncio::zxio::IPV6_RECVPATHMTU, uapi::IPV6_RECVPATHMTU);
1450const_assert_eq!(syncio::zxio::IPV6_PATHMTU, uapi::IPV6_PATHMTU);
1451const_assert_eq!(syncio::zxio::IPV6_DONTFRAG, uapi::IPV6_DONTFRAG);
1452const_assert_eq!(syncio::zxio::IPV6_RECVTCLASS, uapi::IPV6_RECVTCLASS);
1453const_assert_eq!(syncio::zxio::IPV6_TCLASS, uapi::IPV6_TCLASS);
1454const_assert_eq!(syncio::zxio::IPV6_AUTOFLOWLABEL, uapi::IPV6_AUTOFLOWLABEL);
1455const_assert_eq!(syncio::zxio::IPV6_ADDR_PREFERENCES, uapi::IPV6_ADDR_PREFERENCES);
1456const_assert_eq!(syncio::zxio::IPV6_MINHOPCOUNT, uapi::IPV6_MINHOPCOUNT);
1457const_assert_eq!(syncio::zxio::IPV6_ORIGDSTADDR, uapi::IPV6_ORIGDSTADDR);
1458const_assert_eq!(syncio::zxio::IPV6_RECVORIGDSTADDR, uapi::IPV6_RECVORIGDSTADDR);
1459const_assert_eq!(syncio::zxio::IPV6_TRANSPARENT, uapi::IPV6_TRANSPARENT);
1460const_assert_eq!(syncio::zxio::IPV6_UNICAST_IF, uapi::IPV6_UNICAST_IF);
1461const_assert_eq!(syncio::zxio::IPV6_ADD_MEMBERSHIP, uapi::IPV6_ADD_MEMBERSHIP);
1462const_assert_eq!(syncio::zxio::IPV6_DROP_MEMBERSHIP, uapi::IPV6_DROP_MEMBERSHIP);
1463const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_DONT, uapi::IPV6_PMTUDISC_DONT);
1464const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_WANT, uapi::IPV6_PMTUDISC_WANT);
1465const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_DO, uapi::IPV6_PMTUDISC_DO);
1466const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_PROBE, uapi::IPV6_PMTUDISC_PROBE);
1467const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_INTERFACE, uapi::IPV6_PMTUDISC_INTERFACE);
1468const_assert_eq!(syncio::zxio::IPV6_PMTUDISC_OMIT, uapi::IPV6_PMTUDISC_OMIT);
1469const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_TMP, uapi::IPV6_PREFER_SRC_TMP);
1470const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_PUBLIC, uapi::IPV6_PREFER_SRC_PUBLIC);
1471const_assert_eq!(
1472    syncio::zxio::IPV6_PREFER_SRC_PUBTMP_DEFAULT,
1473    uapi::IPV6_PREFER_SRC_PUBTMP_DEFAULT
1474);
1475const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_COA, uapi::IPV6_PREFER_SRC_COA);
1476const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_HOME, uapi::IPV6_PREFER_SRC_HOME);
1477const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_CGA, uapi::IPV6_PREFER_SRC_CGA);
1478const_assert_eq!(syncio::zxio::IPV6_PREFER_SRC_NONCGA, uapi::IPV6_PREFER_SRC_NONCGA);