use super::*; use crate::phy::Medium; use crate::wire::EthernetFrame; use std::os::unix::io::{AsRawFd, RawFd}; use std::{io, mem}; #[derive(Debug)] pub struct RawSocketDesc { protocol: libc::c_short, lower: libc::c_int, ifreq: ifreq, } impl AsRawFd for RawSocketDesc { fn as_raw_fd(&self) -> RawFd { self.lower } } impl RawSocketDesc { pub fn new(name: &str, medium: Medium) -> io::Result { let protocol = match medium { #[cfg(feature = "medium-ethernet")] Medium::Ethernet => imp::ETH_P_ALL, #[cfg(feature = "medium-ip")] Medium::Ip => imp::ETH_P_ALL, #[cfg(feature = "medium-ieee802154")] Medium::Ieee802154 => imp::ETH_P_IEEE802154, }; let lower = unsafe { let lower = libc::socket( libc::AF_PACKET, libc::SOCK_RAW | libc::SOCK_NONBLOCK, protocol.to_be() as i32, ); if lower == -1 { return Err(io::Error::last_os_error()); } lower }; Ok(RawSocketDesc { protocol, lower, ifreq: ifreq_for(name), }) } pub fn interface_mtu(&mut self) -> io::Result { // SIOCGIFMTU returns the IP MTU (typically 1500 bytes.) // smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it. let ip_mtu = ifreq_ioctl(self.lower, &mut self.ifreq, imp::SIOCGIFMTU).map(|mtu| mtu as usize)?; Ok(ip_mtu + EthernetFrame::<&[u8]>::header_len()) } pub fn bind_interface(&mut self) -> io::Result<()> { let sockaddr = libc::sockaddr_ll { sll_family: libc::AF_PACKET as u16, sll_protocol: self.protocol.to_be() as u16, sll_ifindex: ifreq_ioctl(self.lower, &mut self.ifreq, imp::SIOCGIFINDEX)?, sll_hatype: 1, sll_pkttype: 0, sll_halen: 6, sll_addr: [0; 8], }; unsafe { let res = libc::bind( self.lower, &sockaddr as *const libc::sockaddr_ll as *const libc::sockaddr, mem::size_of::() as u32, ); if res == -1 { return Err(io::Error::last_os_error()); } } Ok(()) } pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result { unsafe { let len = libc::recv( self.lower, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(), 0, ); if len == -1 { return Err(io::Error::last_os_error()); } Ok(len as usize) } } pub fn send(&mut self, buffer: &[u8]) -> io::Result { unsafe { let len = libc::send( self.lower, buffer.as_ptr() as *const libc::c_void, buffer.len(), 0, ); if len == -1 { Err(io::Error::last_os_error()).unwrap() } Ok(len as usize) } } } impl Drop for RawSocketDesc { fn drop(&mut self) { unsafe { libc::close(self.lower); } } }