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