| 
1 | 1 | //! Low-level Linux network device access  | 
2 | 2 | //!  | 
 | 3 | +//! The methods in this module take a socket's file descriptor to communicate with  | 
 | 4 | +//! the kernel in their ioctl call:  | 
 | 5 | +//! - glibc uses an `AF_UNIX`, `AF_INET`, or `AF_INET6` socket.  | 
 | 6 | +//! The address family itself does not matter and glibc tries the next address family if socket creation with one fails.  | 
 | 7 | +//! - Android (bionic) uses an `AF_INET` socket.  | 
 | 8 | +//! - Both create the socket with `SOCK_DGRAM|SOCK_CLOEXEC` type/flag.  | 
 | 9 | +//! - The [man-pages] specify, that the ioctl calls "can be used on any socket's file descriptor regardless of the  | 
 | 10 | +//! family or type".  | 
 | 11 | +//!  | 
3 | 12 | //! # References  | 
4 | 13 | //! - [Linux]  | 
5 | 14 | //!  | 
 | 15 | +//! [man-pages]: https://man7.org/linux/man-pages/man7/netdevice.7.html  | 
6 | 16 | //! [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html  | 
7 | 17 | 
  | 
8 | 18 | #[cfg(feature = "alloc")]  | 
9 | 19 | use crate::alloc::string::String;  | 
10 |  | -use crate::fd::OwnedFd;  | 
 | 20 | +use crate::fd::AsFd;  | 
11 | 21 | use crate::io;  | 
12 |  | -use crate::io::Errno;  | 
13 |  | -use crate::net::{socket, AddressFamily, SocketType};  | 
14 |  | - | 
15 |  | -/// Creates a socket used to communicate with the kernel in the ioctl calls.  | 
16 |  | -#[cfg(target_os = "linux")]  | 
17 |  | -pub(crate) fn open_socket() -> io::Result<OwnedFd> {  | 
18 |  | -    if let Ok(fd) = socket(AddressFamily::UNIX, SocketType::DGRAM, None) {  | 
19 |  | -        Ok(fd)  | 
20 |  | -    } else if let Ok(fd) = socket(AddressFamily::INET, SocketType::DGRAM, None) {  | 
21 |  | -        Ok(fd)  | 
22 |  | -    } else if let Ok(fd) = socket(AddressFamily::INET6, SocketType::DGRAM, None) {  | 
23 |  | -        Ok(fd)  | 
24 |  | -    } else {  | 
25 |  | -        Err(Errno::NOENT)  | 
26 |  | -    }  | 
27 |  | -}  | 
28 | 22 | 
 
  | 
29 | 23 | /// `ioctl(fd, SIOCGIFINDEX, ifreq)`—Returns the interface index for a given name.  | 
30 | 24 | ///  | 
 | 25 | +/// See the [module-level documentation] for information about `fd` usage.  | 
 | 26 | +///  | 
31 | 27 | /// # References  | 
32 | 28 | ///  - [Linux]  | 
33 | 29 | ///  | 
 | 30 | +/// [module-level documentation]: self  | 
34 | 31 | /// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html  | 
35 | 32 | #[inline]  | 
36 | 33 | #[doc(alias = "SIOCGIFINDEX")]  | 
37 |  | -#[cfg(target_os = "linux")]  | 
38 |  | -pub fn name_to_index(if_name: &str) -> io::Result<u32> {  | 
39 |  | -    crate::backend::net::netdevice::name_to_index(if_name)  | 
 | 34 | +pub fn name_to_index(fd: impl AsFd, if_name: &str) -> io::Result<u32> {  | 
 | 35 | +    crate::backend::net::netdevice::name_to_index(fd, if_name)  | 
40 | 36 | }  | 
41 | 37 | 
 
  | 
42 | 38 | /// `ioctl(fd, SIOCGIFNAME, ifreq)`—Returns the interface name for a given index.  | 
43 | 39 | ///  | 
 | 40 | +/// See the [module-level documentation] for information about `fd` usage.  | 
 | 41 | +///  | 
44 | 42 | /// # References  | 
45 | 43 | ///  - [Linux]  | 
46 | 44 | ///  | 
 | 45 | +/// [module-level documentation]: self  | 
47 | 46 | /// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html  | 
48 | 47 | #[inline]  | 
49 | 48 | #[doc(alias = "SIOCGIFNAME")]  | 
50 |  | -#[cfg(all(target_os = "linux", feature = "alloc"))]  | 
51 |  | -pub fn index_to_name(index: u32) -> io::Result<String> {  | 
52 |  | -    crate::backend::net::netdevice::index_to_name(index)  | 
 | 49 | +#[cfg(feature = "alloc")]  | 
 | 50 | +pub fn index_to_name(fd: impl AsFd, index: u32) -> io::Result<String> {  | 
 | 51 | +    crate::backend::net::netdevice::index_to_name(fd, index)  | 
53 | 52 | }  | 
54 | 53 | 
 
  | 
55 | 54 | #[cfg(test)]  | 
56 | 55 | mod tests {  | 
57 | 56 |     use crate::backend::net::netdevice::{index_to_name, name_to_index};  | 
 | 57 | +    use crate::net::{AddressFamily, SocketFlags, SocketType};  | 
58 | 58 | 
 
  | 
59 | 59 |     #[test]  | 
60 |  | -    #[cfg(target_os = "linux")]  | 
61 | 60 |     fn test_name_to_index() {  | 
 | 61 | +        let fd = crate::net::socket_with(  | 
 | 62 | +            AddressFamily::INET,  | 
 | 63 | +            SocketType::DGRAM,  | 
 | 64 | +            SocketFlags::CLOEXEC,  | 
 | 65 | +            None,  | 
 | 66 | +        )  | 
 | 67 | +        .unwrap();  | 
 | 68 | + | 
62 | 69 |         let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex")  | 
63 | 70 |             .unwrap()  | 
64 | 71 |             .as_str()  | 
65 | 72 |             .split_at(1)  | 
66 | 73 |             .0  | 
67 | 74 |             .parse::<u32>()  | 
68 | 75 |             .unwrap();  | 
69 |  | -        assert_eq!(Ok(loopback_index), name_to_index("lo"));  | 
 | 76 | +        assert_eq!(Ok(loopback_index), name_to_index(fd, "lo"));  | 
70 | 77 |     }  | 
71 | 78 | 
 
  | 
72 | 79 |     #[test]  | 
73 |  | -    #[cfg(all(target_os = "linux", feature = "alloc"))]  | 
 | 80 | +    #[cfg(feature = "alloc")]  | 
74 | 81 |     fn test_index_to_name() {  | 
 | 82 | +        let fd = crate::net::socket_with(  | 
 | 83 | +            AddressFamily::INET,  | 
 | 84 | +            SocketType::DGRAM,  | 
 | 85 | +            SocketFlags::CLOEXEC,  | 
 | 86 | +            None,  | 
 | 87 | +        )  | 
 | 88 | +        .unwrap();  | 
 | 89 | + | 
75 | 90 |         let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex")  | 
76 | 91 |             .unwrap()  | 
77 | 92 |             .as_str()  | 
78 | 93 |             .split_at(1)  | 
79 | 94 |             .0  | 
80 | 95 |             .parse::<u32>()  | 
81 | 96 |             .unwrap();  | 
82 |  | -        assert_eq!(Ok("lo".to_owned()), index_to_name(loopback_index));  | 
 | 97 | +        assert_eq!(Ok("lo".to_owned()), index_to_name(fd, loopback_index));  | 
83 | 98 |     }  | 
84 | 99 | }  | 
0 commit comments