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