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