smoltcp/phy/sys/
mod.rs

1#![allow(unsafe_code)]
2
3use crate::time::Duration;
4use std::os::unix::io::RawFd;
5use std::{io, mem, ptr};
6
7#[cfg(any(target_os = "linux", target_os = "android"))]
8#[path = "linux.rs"]
9mod imp;
10
11#[cfg(all(
12    feature = "phy-raw_socket",
13    not(any(target_os = "linux", target_os = "android")),
14    unix
15))]
16pub mod bpf;
17#[cfg(all(
18    feature = "phy-raw_socket",
19    any(target_os = "linux", target_os = "android")
20))]
21pub mod raw_socket;
22#[cfg(all(
23    feature = "phy-tuntap_interface",
24    any(target_os = "linux", target_os = "android")
25))]
26pub mod tuntap_interface;
27
28#[cfg(all(
29    feature = "phy-raw_socket",
30    not(any(target_os = "linux", target_os = "android")),
31    unix
32))]
33pub use self::bpf::BpfDevice as RawSocketDesc;
34#[cfg(all(
35    feature = "phy-raw_socket",
36    any(target_os = "linux", target_os = "android")
37))]
38pub use self::raw_socket::RawSocketDesc;
39#[cfg(all(
40    feature = "phy-tuntap_interface",
41    any(target_os = "linux", target_os = "android")
42))]
43pub use self::tuntap_interface::TunTapInterfaceDesc;
44
45/// Wait until given file descriptor becomes readable, but no longer than given timeout.
46pub fn wait(fd: RawFd, duration: Option<Duration>) -> io::Result<()> {
47    unsafe {
48        let mut readfds = {
49            let mut readfds = mem::MaybeUninit::<libc::fd_set>::uninit();
50            libc::FD_ZERO(readfds.as_mut_ptr());
51            libc::FD_SET(fd, readfds.as_mut_ptr());
52            readfds.assume_init()
53        };
54
55        let mut writefds = {
56            let mut writefds = mem::MaybeUninit::<libc::fd_set>::uninit();
57            libc::FD_ZERO(writefds.as_mut_ptr());
58            writefds.assume_init()
59        };
60
61        let mut exceptfds = {
62            let mut exceptfds = mem::MaybeUninit::<libc::fd_set>::uninit();
63            libc::FD_ZERO(exceptfds.as_mut_ptr());
64            exceptfds.assume_init()
65        };
66
67        let mut timeout = libc::timeval {
68            tv_sec: 0,
69            tv_usec: 0,
70        };
71        let timeout_ptr = if let Some(duration) = duration {
72            timeout.tv_sec = duration.secs() as libc::time_t;
73            timeout.tv_usec = (duration.millis() * 1_000) as libc::suseconds_t;
74            &mut timeout as *mut _
75        } else {
76            ptr::null_mut()
77        };
78
79        let res = libc::select(
80            fd + 1,
81            &mut readfds,
82            &mut writefds,
83            &mut exceptfds,
84            timeout_ptr,
85        );
86        if res == -1 {
87            return Err(io::Error::last_os_error());
88        }
89        Ok(())
90    }
91}
92
93#[cfg(all(
94    any(feature = "phy-tuntap_interface", feature = "phy-raw_socket"),
95    unix
96))]
97#[repr(C)]
98#[derive(Debug)]
99struct ifreq {
100    ifr_name: [libc::c_char; libc::IF_NAMESIZE],
101    ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
102}
103
104#[cfg(all(
105    any(feature = "phy-tuntap_interface", feature = "phy-raw_socket"),
106    unix
107))]
108fn ifreq_for(name: &str) -> ifreq {
109    let mut ifreq = ifreq {
110        ifr_name: [0; libc::IF_NAMESIZE],
111        ifr_data: 0,
112    };
113    for (i, byte) in name.as_bytes().iter().enumerate() {
114        ifreq.ifr_name[i] = *byte as libc::c_char
115    }
116    ifreq
117}
118
119#[cfg(all(
120    any(target_os = "linux", target_os = "android"),
121    any(feature = "phy-tuntap_interface", feature = "phy-raw_socket")
122))]
123fn ifreq_ioctl(
124    lower: libc::c_int,
125    ifreq: &mut ifreq,
126    cmd: libc::c_ulong,
127) -> io::Result<libc::c_int> {
128    unsafe {
129        let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
130        if res == -1 {
131            return Err(io::Error::last_os_error());
132        }
133    }
134
135    Ok(ifreq.ifr_data)
136}