tuntap_interface.rs 3.3 KB

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