1 use super::*;
2 use crate::{phy::Medium, wire::EthernetFrame};
3 use std::io;
4 use std::os::unix::io::{AsRawFd, RawFd};
5 
6 #[derive(Debug)]
7 pub struct TunTapInterfaceDesc {
8     lower: libc::c_int,
9     ifreq: ifreq,
10     medium: Medium,
11 }
12 
13 impl AsRawFd for TunTapInterfaceDesc {
as_raw_fd(&self) -> RawFd14     fn as_raw_fd(&self) -> RawFd {
15         self.lower
16     }
17 }
18 
19 impl TunTapInterfaceDesc {
new(name: &str, medium: Medium) -> io::Result<TunTapInterfaceDesc>20     pub fn new(name: &str, medium: Medium) -> io::Result<TunTapInterfaceDesc> {
21         let lower = unsafe {
22             let lower = libc::open(
23                 "/dev/net/tun\0".as_ptr() as *const libc::c_char,
24                 libc::O_RDWR | libc::O_NONBLOCK,
25             );
26             if lower == -1 {
27                 return Err(io::Error::last_os_error());
28             }
29             lower
30         };
31 
32         Ok(TunTapInterfaceDesc {
33             lower,
34             ifreq: ifreq_for(name),
35             medium,
36         })
37     }
38 
attach_interface(&mut self) -> io::Result<()>39     pub fn attach_interface(&mut self) -> io::Result<()> {
40         let mode = match self.medium {
41             #[cfg(feature = "medium-ip")]
42             Medium::Ip => imp::IFF_TUN,
43             #[cfg(feature = "medium-ethernet")]
44             Medium::Ethernet => imp::IFF_TAP,
45             #[cfg(feature = "medium-ieee802154")]
46             Medium::Ieee802154 => todo!(),
47         };
48         self.ifreq.ifr_data = mode | imp::IFF_NO_PI;
49         ifreq_ioctl(self.lower, &mut self.ifreq, imp::TUNSETIFF).map(|_| ())
50     }
51 
interface_mtu(&mut self) -> io::Result<usize>52     pub fn interface_mtu(&mut self) -> io::Result<usize> {
53         let lower = unsafe {
54             let lower = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP);
55             if lower == -1 {
56                 return Err(io::Error::last_os_error());
57             }
58             lower
59         };
60 
61         let ip_mtu = ifreq_ioctl(lower, &mut self.ifreq, imp::SIOCGIFMTU).map(|mtu| mtu as usize);
62 
63         unsafe {
64             libc::close(lower);
65         }
66 
67         // Propagate error after close, to ensure we always close.
68         let ip_mtu = ip_mtu?;
69 
70         // SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
71         // smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
72         let mtu = match self.medium {
73             #[cfg(feature = "medium-ip")]
74             Medium::Ip => ip_mtu,
75             #[cfg(feature = "medium-ethernet")]
76             Medium::Ethernet => ip_mtu + EthernetFrame::<&[u8]>::header_len(),
77             #[cfg(feature = "medium-ieee802154")]
78             Medium::Ieee802154 => todo!(),
79         };
80 
81         Ok(mtu)
82     }
83 
recv(&mut self, buffer: &mut [u8]) -> io::Result<usize>84     pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
85         unsafe {
86             let len = libc::read(
87                 self.lower,
88                 buffer.as_mut_ptr() as *mut libc::c_void,
89                 buffer.len(),
90             );
91             if len == -1 {
92                 return Err(io::Error::last_os_error());
93             }
94             Ok(len as usize)
95         }
96     }
97 
send(&mut self, buffer: &[u8]) -> io::Result<usize>98     pub fn send(&mut self, buffer: &[u8]) -> io::Result<usize> {
99         unsafe {
100             let len = libc::write(
101                 self.lower,
102                 buffer.as_ptr() as *const libc::c_void,
103                 buffer.len(),
104             );
105             if len == -1 {
106                 return Err(io::Error::last_os_error());
107             }
108             Ok(len as usize)
109         }
110     }
111 }
112 
113 impl Drop for TunTapInterfaceDesc {
drop(&mut self)114     fn drop(&mut self) {
115         unsafe {
116             libc::close(self.lower);
117         }
118     }
119 }
120