1#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
7
8use crate::backend::c;
9use crate::backend::conv::{by_mut, c_uint, ret, socklen_t};
10#[cfg(all(target_os = "linux", feature = "time"))]
11use crate::clockid::ClockId;
12use crate::fd::BorrowedFd;
13#[cfg(feature = "alloc")]
14use crate::ffi::CStr;
15use crate::io;
16use crate::net::sockopt::{Ipv4PathMtuDiscovery, Ipv6PathMtuDiscovery, Timeout};
17#[cfg(target_os = "linux")]
18use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
19#[cfg(all(target_os = "linux", feature = "time"))]
20use crate::net::TxTimeFlags;
21use crate::net::{
22 AddressFamily, Ipv4Addr, Ipv6Addr, Protocol, RawProtocol, SocketAddrBuf, SocketAddrV4,
23 SocketAddrV6, SocketType, UCred,
24};
25#[cfg(feature = "alloc")]
26use alloc::borrow::ToOwned as _;
27#[cfg(feature = "alloc")]
28use alloc::string::String;
29use core::mem::{size_of, MaybeUninit};
30use core::time::Duration;
31use linux_raw_sys::general::{__kernel_old_timeval, __kernel_sock_timeval};
32use linux_raw_sys::net::{
33 IPV6_MTU, IPV6_MTU_DISCOVER, IPV6_MULTICAST_IF, IP_MTU, IP_MTU_DISCOVER, IP_MULTICAST_IF,
34};
35#[cfg(target_os = "linux")]
36use linux_raw_sys::xdp::{xdp_mmap_offsets, xdp_statistics, xdp_statistics_v1};
37#[cfg(target_arch = "x86")]
38use {
39 crate::backend::conv::{slice_just_addr, x86_sys},
40 crate::backend::reg::{ArgReg, SocketArg},
41 linux_raw_sys::net::{SYS_GETSOCKOPT, SYS_SETSOCKOPT},
42};
43
44#[inline]
45fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> {
46 let mut optlen: c::socklen_t = size_of::<T>().try_into().unwrap();
47 debug_assert!(
48 optlen as usize >= size_of::<c::c_int>(),
49 "Socket APIs don't ever use `bool` directly"
50 );
51
52 let mut value = MaybeUninit::<T>::uninit();
53 getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
54
55 assert_eq!(
56 optlen as usize,
57 size_of::<T>(),
58 "unexpected getsockopt size"
59 );
60
61 unsafe { Ok(value.assume_init()) }
62}
63
64#[inline]
65fn getsockopt_raw<T>(
66 fd: BorrowedFd<'_>,
67 level: u32,
68 optname: u32,
69 value: &mut MaybeUninit<T>,
70 optlen: &mut c::socklen_t,
71) -> io::Result<()> {
72 #[cfg(not(target_arch = "x86"))]
73 unsafe {
74 ret(syscall!(
75 __NR_getsockopt,
76 fd,
77 c_uint(level),
78 c_uint(optname),
79 value,
80 by_mut(optlen)
81 ))
82 }
83 #[cfg(target_arch = "x86")]
84 unsafe {
85 ret(syscall!(
86 __NR_socketcall,
87 x86_sys(SYS_GETSOCKOPT),
88 slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
89 fd.into(),
90 c_uint(level),
91 c_uint(optname),
92 value.into(),
93 by_mut(optlen),
94 ])
95 ))
96 }
97}
98
99#[inline]
100fn setsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32, value: T) -> io::Result<()> {
101 let optlen = size_of::<T>().try_into().unwrap();
102 debug_assert!(
103 optlen as usize >= size_of::<c::c_int>(),
104 "Socket APIs don't ever use `bool` directly"
105 );
106 setsockopt_raw(fd, level, optname, &value, optlen)
107}
108
109#[inline]
110fn setsockopt_raw<T>(
111 fd: BorrowedFd<'_>,
112 level: u32,
113 optname: u32,
114 ptr: *const T,
115 optlen: c::socklen_t,
116) -> io::Result<()> {
117 #[cfg(not(target_arch = "x86"))]
118 unsafe {
119 ret(syscall_readonly!(
120 __NR_setsockopt,
121 fd,
122 c_uint(level),
123 c_uint(optname),
124 ptr,
125 socklen_t(optlen)
126 ))
127 }
128 #[cfg(target_arch = "x86")]
129 unsafe {
130 ret(syscall_readonly!(
131 __NR_socketcall,
132 x86_sys(SYS_SETSOCKOPT),
133 slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
134 fd.into(),
135 c_uint(level),
136 c_uint(optname),
137 ptr.into(),
138 socklen_t(optlen),
139 ])
140 ))
141 }
142}
143
144#[inline]
145pub(crate) fn socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> {
146 getsockopt(fd, c::SOL_SOCKET, c::SO_TYPE)
147}
148
149#[inline]
150pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> {
151 setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR, from_bool(reuseaddr))
152}
153
154#[inline]
155pub(crate) fn socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
156 getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR).map(to_bool)
157}
158
159#[inline]
160pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
161 setsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST, from_bool(broadcast))
162}
163
164#[inline]
165pub(crate) fn socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> {
166 getsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST).map(to_bool)
167}
168
169#[inline]
170pub(crate) fn set_socket_linger(fd: BorrowedFd<'_>, linger: Option<Duration>) -> io::Result<()> {
171 let l_linger = if let Some(linger) = linger {
173 duration_to_secs(linger)?
174 } else {
175 0
176 };
177 let linger = c::linger {
178 l_onoff: c::c_int::from(linger.is_some()),
179 l_linger,
180 };
181 setsockopt(fd, c::SOL_SOCKET, c::SO_LINGER, linger)
182}
183
184#[inline]
185pub(crate) fn socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> {
186 let linger: c::linger = getsockopt(fd, c::SOL_SOCKET, c::SO_LINGER)?;
187 Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64)))
188}
189
190#[inline]
191pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> {
192 setsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED, from_bool(passcred))
193}
194
195#[inline]
196pub(crate) fn socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> {
197 getsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED).map(to_bool)
198}
199
200#[inline]
201pub(crate) fn set_socket_timeout(
202 fd: BorrowedFd<'_>,
203 id: Timeout,
204 timeout: Option<Duration>,
205) -> io::Result<()> {
206 let time = duration_to_linux_sock_timeval(timeout)?;
207 let optname = match id {
208 Timeout::Recv => c::SO_RCVTIMEO_NEW,
209 Timeout::Send => c::SO_SNDTIMEO_NEW,
210 };
211 match setsockopt(fd, c::SOL_SOCKET, optname, time) {
212 Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
213 set_socket_timeout_old(fd, id, timeout)
214 }
215 otherwise => otherwise,
216 }
217}
218
219fn set_socket_timeout_old(
222 fd: BorrowedFd<'_>,
223 id: Timeout,
224 timeout: Option<Duration>,
225) -> io::Result<()> {
226 let time = duration_to_linux_old_timeval(timeout)?;
227 let optname = match id {
228 Timeout::Recv => c::SO_RCVTIMEO_OLD,
229 Timeout::Send => c::SO_SNDTIMEO_OLD,
230 };
231 setsockopt(fd, c::SOL_SOCKET, optname, time)
232}
233
234#[inline]
235pub(crate) fn socket_timeout(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
236 let optname = match id {
237 Timeout::Recv => c::SO_RCVTIMEO_NEW,
238 Timeout::Send => c::SO_SNDTIMEO_NEW,
239 };
240 let time: __kernel_sock_timeval = match getsockopt(fd, c::SOL_SOCKET, optname) {
241 Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
242 return socket_timeout_old(fd, id)
243 }
244 otherwise => otherwise?,
245 };
246 Ok(duration_from_linux_sock_timeval(time))
247}
248
249fn socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
252 let optname = match id {
253 Timeout::Recv => c::SO_RCVTIMEO_OLD,
254 Timeout::Send => c::SO_SNDTIMEO_OLD,
255 };
256 let time: __kernel_old_timeval = getsockopt(fd, c::SOL_SOCKET, optname)?;
257 Ok(duration_from_linux_old_timeval(time))
258}
259
260#[inline]
262fn duration_from_linux_sock_timeval(time: __kernel_sock_timeval) -> Option<Duration> {
263 if time.tv_sec == 0 && time.tv_usec == 0 {
264 None
265 } else {
266 Some(Duration::from_secs(time.tv_sec as u64) + Duration::from_micros(time.tv_usec as u64))
267 }
268}
269
270fn duration_from_linux_old_timeval(time: __kernel_old_timeval) -> Option<Duration> {
273 if time.tv_sec == 0 && time.tv_usec == 0 {
274 None
275 } else {
276 Some(Duration::from_secs(time.tv_sec as u64) + Duration::from_micros(time.tv_usec as u64))
277 }
278}
279
280#[inline]
282fn duration_to_linux_sock_timeval(timeout: Option<Duration>) -> io::Result<__kernel_sock_timeval> {
283 Ok(match timeout {
284 Some(timeout) => {
285 if timeout == Duration::ZERO {
286 return Err(io::Errno::INVAL);
287 }
288
289 let ts = crate::timespec::Timespec {
290 tv_sec: timeout
291 .as_secs()
292 .try_into()
293 .unwrap_or(crate::timespec::Secs::MAX),
294 tv_nsec: timeout.subsec_nanos() as _,
295 };
296 let (sec, usec) = ts.to_sec_usec().unwrap_or((crate::timespec::Secs::MAX, 0));
297 let mut timeout = __kernel_sock_timeval {
298 tv_sec: sec.try_into().unwrap_or(i64::MAX),
299 tv_usec: usec as _,
300 };
301 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
302 timeout.tv_usec = 1;
303 }
304 timeout
305 }
306 None => __kernel_sock_timeval {
307 tv_sec: 0,
308 tv_usec: 0,
309 },
310 })
311}
312
313fn duration_to_linux_old_timeval(timeout: Option<Duration>) -> io::Result<__kernel_old_timeval> {
316 Ok(match timeout {
317 Some(timeout) => {
318 if timeout == Duration::ZERO {
319 return Err(io::Errno::INVAL);
320 }
321
322 let ts = crate::timespec::Timespec {
323 tv_sec: timeout
324 .as_secs()
325 .try_into()
326 .unwrap_or(crate::timespec::Secs::MAX),
327 tv_nsec: timeout.subsec_nanos() as _,
328 };
329 let (sec, usec) = ts.to_sec_usec().unwrap_or((crate::timespec::Secs::MAX, 0));
330 let mut timeout = __kernel_old_timeval {
331 tv_sec: sec.try_into().unwrap_or(c::c_long::MAX),
332 tv_usec: usec as _,
333 };
334 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
335 timeout.tv_usec = 1;
336 }
337 timeout
338 }
339 None => __kernel_old_timeval {
340 tv_sec: 0,
341 tv_usec: 0,
342 },
343 })
344}
345
346#[inline]
347pub(crate) fn socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> {
348 let err: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_ERROR)?;
349 Ok(if err == 0 {
350 Ok(())
351 } else {
352 Err(io::Errno::from_raw_os_error(err))
353 })
354}
355
356#[inline]
357pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> {
358 setsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE, from_bool(keepalive))
359}
360
361#[inline]
362pub(crate) fn socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> {
363 getsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE).map(to_bool)
364}
365
366#[inline]
367pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
368 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
369 setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF, size)
370}
371
372#[inline]
373pub(crate) fn set_socket_recv_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
374 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
375 setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUFFORCE, size)
376}
377
378#[inline]
379pub(crate) fn socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
380 getsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF).map(|size: u32| size as usize)
381}
382
383#[inline]
384pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
385 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
386 setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF, size)
387}
388
389#[inline]
390pub(crate) fn set_socket_send_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
391 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
392 setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUFFORCE, size)
393}
394
395#[inline]
396pub(crate) fn socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
397 getsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF).map(|size: u32| size as usize)
398}
399
400#[inline]
401pub(crate) fn socket_domain(fd: BorrowedFd<'_>) -> io::Result<AddressFamily> {
402 let domain: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_DOMAIN)?;
403 Ok(AddressFamily(
404 domain.try_into().map_err(|_| io::Errno::OPNOTSUPP)?,
405 ))
406}
407
408#[inline]
409pub(crate) fn socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
410 getsockopt(fd, c::SOL_SOCKET, c::SO_ACCEPTCONN).map(to_bool)
411}
412
413#[inline]
414pub(crate) fn set_socket_oobinline(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
415 setsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE, from_bool(value))
416}
417
418#[inline]
419pub(crate) fn socket_oobinline(fd: BorrowedFd<'_>) -> io::Result<bool> {
420 getsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE).map(to_bool)
421}
422
423#[inline]
424pub(crate) fn set_socket_reuseport(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
425 setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT, from_bool(value))
426}
427
428#[inline]
429pub(crate) fn socket_reuseport(fd: BorrowedFd<'_>) -> io::Result<bool> {
430 getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT).map(to_bool)
431}
432
433#[inline]
434pub(crate) fn socket_protocol(fd: BorrowedFd<'_>) -> io::Result<Option<Protocol>> {
435 getsockopt(fd, c::SOL_SOCKET, c::SO_PROTOCOL)
436 .map(|raw: u32| RawProtocol::new(raw).map(Protocol::from_raw))
437}
438
439#[inline]
440pub(crate) fn socket_cookie(fd: BorrowedFd<'_>) -> io::Result<u64> {
441 getsockopt(fd, c::SOL_SOCKET, c::SO_COOKIE)
442}
443
444#[inline]
445pub(crate) fn socket_incoming_cpu(fd: BorrowedFd<'_>) -> io::Result<u32> {
446 getsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU)
447}
448
449#[inline]
450pub(crate) fn set_socket_incoming_cpu(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
451 setsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU, value)
452}
453
454#[inline]
455pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
456 setsockopt(fd, c::IPPROTO_IP, c::IP_TTL, ttl)
457}
458
459#[inline]
460pub(crate) fn ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
461 getsockopt(fd, c::IPPROTO_IP, c::IP_TTL)
462}
463
464#[inline]
465pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> {
466 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY, from_bool(only_v6))
467}
468
469#[inline]
470pub(crate) fn ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> {
471 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY).map(to_bool)
472}
473
474#[inline]
475pub(crate) fn ip_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
476 getsockopt(fd, c::IPPROTO_IP, IP_MTU)
477}
478
479#[inline]
480pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
481 getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU)
482}
483
484#[inline]
485pub(crate) fn set_ip_mtu_discover(
486 fd: BorrowedFd<'_>,
487 value: Ipv4PathMtuDiscovery,
488) -> io::Result<()> {
489 setsockopt(fd, c::IPPROTO_IP, IP_MTU_DISCOVER, value)
490}
491
492#[inline]
493pub(crate) fn ip_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv4PathMtuDiscovery> {
494 getsockopt(fd, c::IPPROTO_IP, IP_MTU_DISCOVER)
495}
496
497#[inline]
498pub(crate) fn set_ipv6_mtu_discover(
499 fd: BorrowedFd<'_>,
500 value: Ipv6PathMtuDiscovery,
501) -> io::Result<()> {
502 setsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU_DISCOVER, value)
503}
504
505#[inline]
506pub(crate) fn ipv6_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv6PathMtuDiscovery> {
507 getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU_DISCOVER)
508}
509
510#[inline]
511pub(crate) fn set_ip_multicast_if_with_ifindex(
512 fd: BorrowedFd<'_>,
513 multiaddr: &Ipv4Addr,
514 address: &Ipv4Addr,
515 ifindex: u32,
516) -> io::Result<()> {
517 let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
518 setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, mreqn)
519}
520
521#[inline]
522pub(crate) fn set_ip_multicast_if(fd: BorrowedFd<'_>, value: &Ipv4Addr) -> io::Result<()> {
523 setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, to_imr_addr(value))
524}
525
526#[inline]
527pub(crate) fn ip_multicast_if(fd: BorrowedFd<'_>) -> io::Result<Ipv4Addr> {
528 getsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF).map(from_in_addr)
529}
530
531#[inline]
532pub(crate) fn set_ipv6_multicast_if(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
533 setsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF, value as c::c_int)
534}
535
536#[inline]
537pub(crate) fn ipv6_multicast_if(fd: BorrowedFd<'_>) -> io::Result<u32> {
538 getsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF)
539}
540
541#[inline]
542pub(crate) fn set_ip_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
543 setsockopt(
544 fd,
545 c::IPPROTO_IP,
546 c::IP_MULTICAST_LOOP,
547 from_bool(multicast_loop),
548 )
549}
550
551#[inline]
552pub(crate) fn ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
553 getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_LOOP).map(to_bool)
554}
555
556#[inline]
557pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> {
558 setsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl)
559}
560
561#[inline]
562pub(crate) fn ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
563 getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL)
564}
565
566#[inline]
567pub(crate) fn set_ipv6_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
568 setsockopt(
569 fd,
570 c::IPPROTO_IPV6,
571 c::IPV6_MULTICAST_LOOP,
572 from_bool(multicast_loop),
573 )
574}
575
576#[inline]
577pub(crate) fn ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
578 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP).map(to_bool)
579}
580
581#[inline]
582pub(crate) fn set_ipv6_multicast_hops(fd: BorrowedFd<'_>, multicast_hops: u32) -> io::Result<()> {
583 setsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS, multicast_hops)
584}
585
586#[inline]
587pub(crate) fn ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> {
588 getsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS)
589}
590
591#[inline]
592pub(crate) fn set_ip_add_membership(
593 fd: BorrowedFd<'_>,
594 multiaddr: &Ipv4Addr,
595 interface: &Ipv4Addr,
596) -> io::Result<()> {
597 let mreq = to_ip_mreq(multiaddr, interface);
598 setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
599}
600
601#[inline]
602pub(crate) fn set_ip_add_membership_with_ifindex(
603 fd: BorrowedFd<'_>,
604 multiaddr: &Ipv4Addr,
605 address: &Ipv4Addr,
606 ifindex: u32,
607) -> io::Result<()> {
608 let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
609 setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreqn)
610}
611
612#[inline]
613pub(crate) fn set_ip_add_source_membership(
614 fd: BorrowedFd<'_>,
615 multiaddr: &Ipv4Addr,
616 interface: &Ipv4Addr,
617 sourceaddr: &Ipv4Addr,
618) -> io::Result<()> {
619 let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
620 setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_SOURCE_MEMBERSHIP, mreq_source)
621}
622
623#[inline]
624pub(crate) fn set_ip_drop_source_membership(
625 fd: BorrowedFd<'_>,
626 multiaddr: &Ipv4Addr,
627 interface: &Ipv4Addr,
628 sourceaddr: &Ipv4Addr,
629) -> io::Result<()> {
630 let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
631 setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_SOURCE_MEMBERSHIP, mreq_source)
632}
633
634#[inline]
635pub(crate) fn set_ipv6_add_membership(
636 fd: BorrowedFd<'_>,
637 multiaddr: &Ipv6Addr,
638 interface: u32,
639) -> io::Result<()> {
640 let mreq = to_ipv6mr(multiaddr, interface);
641 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_ADD_MEMBERSHIP, mreq)
642}
643
644#[inline]
645pub(crate) fn set_ip_drop_membership(
646 fd: BorrowedFd<'_>,
647 multiaddr: &Ipv4Addr,
648 interface: &Ipv4Addr,
649) -> io::Result<()> {
650 let mreq = to_ip_mreq(multiaddr, interface);
651 setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
652}
653
654#[inline]
655pub(crate) fn set_ip_drop_membership_with_ifindex(
656 fd: BorrowedFd<'_>,
657 multiaddr: &Ipv4Addr,
658 address: &Ipv4Addr,
659 ifindex: u32,
660) -> io::Result<()> {
661 let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
662 setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreqn)
663}
664
665#[inline]
666pub(crate) fn set_ipv6_drop_membership(
667 fd: BorrowedFd<'_>,
668 multiaddr: &Ipv6Addr,
669 interface: u32,
670) -> io::Result<()> {
671 let mreq = to_ipv6mr(multiaddr, interface);
672 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_DROP_MEMBERSHIP, mreq)
673}
674
675#[inline]
676pub(crate) fn ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> {
677 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8)
678}
679
680#[inline]
681pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> {
682 let hops = match hops {
683 Some(hops) => hops.into(),
684 None => -1,
685 };
686 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, hops)
687}
688
689#[inline]
690pub(crate) fn set_ip_tos(fd: BorrowedFd<'_>, value: u8) -> io::Result<()> {
691 setsockopt(fd, c::IPPROTO_IP, c::IP_TOS, i32::from(value))
692}
693
694#[inline]
695pub(crate) fn ip_tos(fd: BorrowedFd<'_>) -> io::Result<u8> {
696 let value: i32 = getsockopt(fd, c::IPPROTO_IP, c::IP_TOS)?;
697 Ok(value as u8)
698}
699
700#[inline]
701pub(crate) fn set_ip_recvtos(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
702 setsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS, from_bool(value))
703}
704
705#[inline]
706pub(crate) fn ip_recvtos(fd: BorrowedFd<'_>) -> io::Result<bool> {
707 getsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS).map(to_bool)
708}
709
710#[inline]
711pub(crate) fn set_ipv6_recvtclass(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
712 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS, from_bool(value))
713}
714
715#[inline]
716pub(crate) fn ipv6_recvtclass(fd: BorrowedFd<'_>) -> io::Result<bool> {
717 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS).map(to_bool)
718}
719
720#[inline]
721pub(crate) fn set_ip_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
722 setsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND, from_bool(value))
723}
724
725#[inline]
726pub(crate) fn ip_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
727 getsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND).map(to_bool)
728}
729
730#[inline]
731pub(crate) fn set_ipv6_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
732 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND, from_bool(value))
733}
734
735#[inline]
736pub(crate) fn ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
737 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool)
738}
739
740#[inline]
741pub(crate) fn ip_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV4> {
742 let level = c::IPPROTO_IP;
743 let optname = c::SO_ORIGINAL_DST;
744 let mut addr = SocketAddrBuf::new();
745
746 getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
747
748 Ok(unsafe { addr.into_any() }.try_into().unwrap())
749}
750
751#[inline]
752pub(crate) fn ipv6_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV6> {
753 let level = c::IPPROTO_IPV6;
754 let optname = c::IP6T_SO_ORIGINAL_DST;
755 let mut addr = SocketAddrBuf::new();
756
757 getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
758
759 Ok(unsafe { addr.into_any() }.try_into().unwrap())
760}
761
762#[inline]
763pub(crate) fn set_ipv6_tclass(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
764 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS, value)
765}
766
767#[inline]
768pub(crate) fn ipv6_tclass(fd: BorrowedFd<'_>) -> io::Result<u32> {
769 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS)
770}
771
772#[inline]
773pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> {
774 setsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY, from_bool(nodelay))
775}
776
777#[inline]
778pub(crate) fn tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> {
779 getsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY).map(to_bool)
780}
781
782#[inline]
783pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
784 setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT, count)
785}
786
787#[inline]
788pub(crate) fn tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
789 getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT)
790}
791
792#[inline]
793pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
794 let secs: c::c_uint = duration_to_secs(duration)?;
795 setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE, secs)
796}
797
798#[inline]
799pub(crate) fn tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
800 let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE)?;
801 Ok(Duration::from_secs(secs.into()))
802}
803
804#[inline]
805pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
806 let secs: c::c_uint = duration_to_secs(duration)?;
807 setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL, secs)
808}
809
810#[inline]
811pub(crate) fn tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
812 let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL)?;
813 Ok(Duration::from_secs(secs.into()))
814}
815
816#[inline]
817pub(crate) fn set_tcp_user_timeout(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
818 setsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT, value)
819}
820
821#[inline]
822pub(crate) fn tcp_user_timeout(fd: BorrowedFd<'_>) -> io::Result<u32> {
823 getsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT)
824}
825
826#[inline]
827pub(crate) fn set_tcp_quickack(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
828 setsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK, from_bool(value))
829}
830
831#[inline]
832pub(crate) fn tcp_quickack(fd: BorrowedFd<'_>) -> io::Result<bool> {
833 getsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK).map(to_bool)
834}
835
836#[inline]
837pub(crate) fn set_tcp_congestion(fd: BorrowedFd<'_>, value: &str) -> io::Result<()> {
838 let level = c::IPPROTO_TCP;
839 let optname = c::TCP_CONGESTION;
840 let optlen = value.len().try_into().unwrap();
841 setsockopt_raw(fd, level, optname, value.as_ptr(), optlen)
842}
843
844#[cfg(feature = "alloc")]
845#[inline]
846pub(crate) fn tcp_congestion(fd: BorrowedFd<'_>) -> io::Result<String> {
847 const OPTLEN: c::socklen_t = 16;
848
849 let level = c::IPPROTO_TCP;
850 let optname = c::TCP_CONGESTION;
851 let mut value = MaybeUninit::<[MaybeUninit<u8>; OPTLEN as usize]>::uninit();
852 let mut optlen = OPTLEN;
853 getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
854 unsafe {
855 let value = value.assume_init();
856 let slice: &[u8] = core::mem::transmute(&value[..optlen as usize]);
857 assert!(slice.contains(&b'\0'));
858 Ok(
859 core::str::from_utf8(CStr::from_ptr(slice.as_ptr().cast()).to_bytes())
860 .unwrap()
861 .to_owned(),
862 )
863 }
864}
865
866#[inline]
867pub(crate) fn set_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
868 setsockopt(
869 fd,
870 c::IPPROTO_TCP,
871 c::TCP_THIN_LINEAR_TIMEOUTS,
872 from_bool(value),
873 )
874}
875
876#[inline]
877pub(crate) fn tcp_thin_linear_timeouts(fd: BorrowedFd<'_>) -> io::Result<bool> {
878 getsockopt(fd, c::IPPROTO_TCP, c::TCP_THIN_LINEAR_TIMEOUTS).map(to_bool)
879}
880
881#[inline]
882pub(crate) fn set_tcp_cork(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
883 setsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK, from_bool(value))
884}
885
886#[inline]
887pub(crate) fn tcp_cork(fd: BorrowedFd<'_>) -> io::Result<bool> {
888 getsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK).map(to_bool)
889}
890
891#[inline]
892pub(crate) fn socket_peercred(fd: BorrowedFd<'_>) -> io::Result<UCred> {
893 getsockopt(fd, c::SOL_SOCKET, linux_raw_sys::net::SO_PEERCRED)
894}
895
896#[cfg(all(target_os = "linux", feature = "time"))]
897#[inline]
898pub(crate) fn set_txtime(
899 fd: BorrowedFd<'_>,
900 clockid: ClockId,
901 flags: TxTimeFlags,
902) -> io::Result<()> {
903 setsockopt(
904 fd,
905 c::SOL_SOCKET,
906 c::SO_TXTIME,
907 c::sock_txtime {
908 clockid: clockid as _,
909 flags: flags.bits(),
910 },
911 )
912}
913
914#[cfg(all(target_os = "linux", feature = "time"))]
915#[inline]
916pub(crate) fn get_txtime(fd: BorrowedFd<'_>) -> io::Result<(ClockId, TxTimeFlags)> {
917 let txtime: c::sock_txtime = getsockopt(fd, c::SOL_SOCKET, c::SO_TXTIME)?;
918
919 Ok((
920 txtime.clockid.try_into().map_err(|_| io::Errno::RANGE)?,
921 TxTimeFlags::from_bits(txtime.flags).ok_or(io::Errno::RANGE)?,
922 ))
923}
924
925#[cfg(target_os = "linux")]
926#[inline]
927pub(crate) fn set_xdp_umem_reg(fd: BorrowedFd<'_>, value: XdpUmemReg) -> io::Result<()> {
928 setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_REG, value)
929}
930
931#[cfg(target_os = "linux")]
932#[inline]
933pub(crate) fn set_xdp_umem_fill_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
934 setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_FILL_RING, value)
935}
936
937#[cfg(target_os = "linux")]
938#[inline]
939pub(crate) fn set_xdp_umem_completion_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
940 setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_COMPLETION_RING, value)
941}
942
943#[cfg(target_os = "linux")]
944#[inline]
945pub(crate) fn set_xdp_tx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
946 setsockopt(fd, c::SOL_XDP, c::XDP_TX_RING, value)
947}
948
949#[cfg(target_os = "linux")]
950#[inline]
951pub(crate) fn set_xdp_rx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
952 setsockopt(fd, c::SOL_XDP, c::XDP_RX_RING, value)
953}
954
955#[cfg(target_os = "linux")]
956#[inline]
957pub(crate) fn xdp_mmap_offsets(fd: BorrowedFd<'_>) -> io::Result<XdpMmapOffsets> {
958 let mut optlen = size_of::<xdp_mmap_offsets>().try_into().unwrap();
967 debug_assert!(
968 optlen as usize >= size_of::<c::c_int>(),
969 "Socket APIs don't ever use `bool` directly"
970 );
971 let mut value = MaybeUninit::<xdp_mmap_offsets>::zeroed();
972 getsockopt_raw(fd, c::SOL_XDP, c::XDP_MMAP_OFFSETS, &mut value, &mut optlen)?;
973
974 if optlen as usize == size_of::<c::xdp_mmap_offsets_v1>() {
975 let xpd_mmap_offsets = unsafe { value.assume_init() };
978 Ok(XdpMmapOffsets {
979 rx: XdpRingOffset {
980 producer: xpd_mmap_offsets.rx.producer,
981 consumer: xpd_mmap_offsets.rx.consumer,
982 desc: xpd_mmap_offsets.rx.desc,
983 flags: None,
984 },
985 tx: XdpRingOffset {
986 producer: xpd_mmap_offsets.rx.flags,
987 consumer: xpd_mmap_offsets.tx.producer,
988 desc: xpd_mmap_offsets.tx.consumer,
989 flags: None,
990 },
991 fr: XdpRingOffset {
992 producer: xpd_mmap_offsets.tx.desc,
993 consumer: xpd_mmap_offsets.tx.flags,
994 desc: xpd_mmap_offsets.fr.producer,
995 flags: None,
996 },
997 cr: XdpRingOffset {
998 producer: xpd_mmap_offsets.fr.consumer,
999 consumer: xpd_mmap_offsets.fr.desc,
1000 desc: xpd_mmap_offsets.fr.flags,
1001 flags: None,
1002 },
1003 })
1004 } else {
1005 assert_eq!(
1006 optlen as usize,
1007 size_of::<xdp_mmap_offsets>(),
1008 "unexpected getsockopt size"
1009 );
1010 let xpd_mmap_offsets = unsafe { value.assume_init() };
1013 Ok(XdpMmapOffsets {
1014 rx: XdpRingOffset {
1015 producer: xpd_mmap_offsets.rx.producer,
1016 consumer: xpd_mmap_offsets.rx.consumer,
1017 desc: xpd_mmap_offsets.rx.desc,
1018 flags: Some(xpd_mmap_offsets.rx.flags),
1019 },
1020 tx: XdpRingOffset {
1021 producer: xpd_mmap_offsets.tx.producer,
1022 consumer: xpd_mmap_offsets.tx.consumer,
1023 desc: xpd_mmap_offsets.tx.desc,
1024 flags: Some(xpd_mmap_offsets.tx.flags),
1025 },
1026 fr: XdpRingOffset {
1027 producer: xpd_mmap_offsets.fr.producer,
1028 consumer: xpd_mmap_offsets.fr.consumer,
1029 desc: xpd_mmap_offsets.fr.desc,
1030 flags: Some(xpd_mmap_offsets.fr.flags),
1031 },
1032 cr: XdpRingOffset {
1033 producer: xpd_mmap_offsets.cr.producer,
1034 consumer: xpd_mmap_offsets.cr.consumer,
1035 desc: xpd_mmap_offsets.cr.desc,
1036 flags: Some(xpd_mmap_offsets.cr.flags),
1037 },
1038 })
1039 }
1040}
1041
1042#[cfg(target_os = "linux")]
1043#[inline]
1044pub(crate) fn xdp_statistics(fd: BorrowedFd<'_>) -> io::Result<XdpStatistics> {
1045 let mut optlen = size_of::<xdp_statistics>().try_into().unwrap();
1046 debug_assert!(
1047 optlen as usize >= size_of::<c::c_int>(),
1048 "Socket APIs don't ever use `bool` directly"
1049 );
1050 let mut value = MaybeUninit::<xdp_statistics>::zeroed();
1051 getsockopt_raw(fd, c::SOL_XDP, c::XDP_STATISTICS, &mut value, &mut optlen)?;
1052
1053 if optlen as usize == size_of::<xdp_statistics_v1>() {
1054 let xdp_statistics = unsafe { value.assume_init() };
1057 Ok(XdpStatistics {
1058 rx_dropped: xdp_statistics.rx_dropped,
1059 rx_invalid_descs: xdp_statistics.rx_dropped,
1060 tx_invalid_descs: xdp_statistics.rx_dropped,
1061 rx_ring_full: None,
1062 rx_fill_ring_empty_descs: None,
1063 tx_ring_empty_descs: None,
1064 })
1065 } else {
1066 assert_eq!(
1067 optlen as usize,
1068 size_of::<xdp_statistics>(),
1069 "unexpected getsockopt size"
1070 );
1071 let xdp_statistics = unsafe { value.assume_init() };
1074 Ok(XdpStatistics {
1075 rx_dropped: xdp_statistics.rx_dropped,
1076 rx_invalid_descs: xdp_statistics.rx_invalid_descs,
1077 tx_invalid_descs: xdp_statistics.tx_invalid_descs,
1078 rx_ring_full: Some(xdp_statistics.rx_ring_full),
1079 rx_fill_ring_empty_descs: Some(xdp_statistics.rx_fill_ring_empty_descs),
1080 tx_ring_empty_descs: Some(xdp_statistics.tx_ring_empty_descs),
1081 })
1082 }
1083}
1084
1085#[cfg(target_os = "linux")]
1086#[inline]
1087pub(crate) fn xdp_options(fd: BorrowedFd<'_>) -> io::Result<XdpOptionsFlags> {
1088 getsockopt(fd, c::SOL_XDP, c::XDP_OPTIONS)
1089}
1090
1091#[inline]
1092fn from_in_addr(in_addr: c::in_addr) -> Ipv4Addr {
1093 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1094}
1095
1096#[inline]
1097fn to_ip_mreq(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
1098 c::ip_mreq {
1099 imr_multiaddr: to_imr_addr(multiaddr),
1100 imr_interface: to_imr_addr(interface),
1101 }
1102}
1103
1104#[inline]
1105fn to_ip_mreqn(multiaddr: &Ipv4Addr, address: &Ipv4Addr, ifindex: i32) -> c::ip_mreqn {
1106 c::ip_mreqn {
1107 imr_multiaddr: to_imr_addr(multiaddr),
1108 imr_address: to_imr_addr(address),
1109 imr_ifindex: ifindex,
1110 }
1111}
1112
1113#[inline]
1114fn to_imr_source(
1115 multiaddr: &Ipv4Addr,
1116 interface: &Ipv4Addr,
1117 sourceaddr: &Ipv4Addr,
1118) -> c::ip_mreq_source {
1119 c::ip_mreq_source {
1120 imr_multiaddr: to_imr_addr(multiaddr).s_addr,
1121 imr_interface: to_imr_addr(interface).s_addr,
1122 imr_sourceaddr: to_imr_addr(sourceaddr).s_addr,
1123 }
1124}
1125
1126#[inline]
1127fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr {
1128 c::in_addr {
1129 s_addr: u32::from_ne_bytes(addr.octets()),
1130 }
1131}
1132
1133#[inline]
1134fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq {
1135 c::ipv6_mreq {
1136 ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr),
1137 ipv6mr_ifindex: to_ipv6mr_interface(interface),
1138 }
1139}
1140
1141#[inline]
1142fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr {
1143 c::in6_addr {
1144 in6_u: linux_raw_sys::net::in6_addr__bindgen_ty_1 {
1145 u6_addr8: multiaddr.octets(),
1146 },
1147 }
1148}
1149
1150#[inline]
1151fn to_ipv6mr_interface(interface: u32) -> c::c_int {
1152 interface as c::c_int
1153}
1154
1155#[inline]
1156fn from_bool(value: bool) -> c::c_uint {
1157 c::c_uint::from(value)
1158}
1159
1160#[inline]
1161fn to_bool(value: c::c_uint) -> bool {
1162 value != 0
1163}
1164
1165#[inline]
1167fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
1168 let mut secs = duration.as_secs();
1169 if duration.subsec_nanos() != 0 {
1170 secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
1171 }
1172 T::try_from(secs).map_err(|_e| io::Errno::INVAL)
1173}