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