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