smoltcp/phy/
raw_socket.rs

1use std::cell::RefCell;
2use std::io;
3use std::os::unix::io::{AsRawFd, RawFd};
4use std::rc::Rc;
5use std::vec::Vec;
6
7use crate::phy::{self, sys, Device, DeviceCapabilities, Medium};
8use crate::time::Instant;
9
10/// A socket that captures or transmits the complete frame.
11#[derive(Debug)]
12pub struct RawSocket {
13    medium: Medium,
14    lower: Rc<RefCell<sys::RawSocketDesc>>,
15    mtu: usize,
16}
17
18impl AsRawFd for RawSocket {
19    fn as_raw_fd(&self) -> RawFd {
20        self.lower.borrow().as_raw_fd()
21    }
22}
23
24impl RawSocket {
25    /// Creates a raw socket, bound to the interface called `name`.
26    ///
27    /// This requires superuser privileges or a corresponding capability bit
28    /// set on the executable.
29    pub fn new(name: &str, medium: Medium) -> io::Result<RawSocket> {
30        let mut lower = sys::RawSocketDesc::new(name, medium)?;
31        lower.bind_interface()?;
32
33        let mut mtu = lower.interface_mtu()?;
34
35        #[cfg(feature = "medium-ieee802154")]
36        if medium == Medium::Ieee802154 {
37            // SIOCGIFMTU returns 127 - (ACK_PSDU - FCS - 1) - FCS.
38            //                    127 - (5 - 2 - 1) - 2 = 123
39            // For IEEE802154, we want to add (ACK_PSDU - FCS - 1), since that is what SIOCGIFMTU
40            // uses as the size of the link layer header.
41            //
42            // https://github.com/torvalds/linux/blob/7475e51b87969e01a6812eac713a1c8310372e8a/net/mac802154/iface.c#L541
43            mtu += 2;
44        }
45
46        #[cfg(feature = "medium-ethernet")]
47        if medium == Medium::Ethernet {
48            // SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
49            // smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
50            mtu += crate::wire::EthernetFrame::<&[u8]>::header_len()
51        }
52
53        Ok(RawSocket {
54            medium,
55            lower: Rc::new(RefCell::new(lower)),
56            mtu,
57        })
58    }
59}
60
61impl Device for RawSocket {
62    type RxToken<'a> = RxToken
63    where
64        Self: 'a;
65    type TxToken<'a> = TxToken
66    where
67        Self: 'a;
68
69    fn capabilities(&self) -> DeviceCapabilities {
70        DeviceCapabilities {
71            max_transmission_unit: self.mtu,
72            medium: self.medium,
73            ..DeviceCapabilities::default()
74        }
75    }
76
77    fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
78        let mut lower = self.lower.borrow_mut();
79        let mut buffer = vec![0; self.mtu];
80        match lower.recv(&mut buffer[..]) {
81            Ok(size) => {
82                buffer.resize(size, 0);
83                let rx = RxToken { buffer };
84                let tx = TxToken {
85                    lower: self.lower.clone(),
86                };
87                Some((rx, tx))
88            }
89            Err(err) if err.kind() == io::ErrorKind::WouldBlock => None,
90            Err(err) => panic!("{}", err),
91        }
92    }
93
94    fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
95        Some(TxToken {
96            lower: self.lower.clone(),
97        })
98    }
99}
100
101#[doc(hidden)]
102pub struct RxToken {
103    buffer: Vec<u8>,
104}
105
106impl phy::RxToken for RxToken {
107    fn consume<R, F>(self, f: F) -> R
108    where
109        F: FnOnce(&[u8]) -> R,
110    {
111        f(&self.buffer[..])
112    }
113}
114
115#[doc(hidden)]
116pub struct TxToken {
117    lower: Rc<RefCell<sys::RawSocketDesc>>,
118}
119
120impl phy::TxToken for TxToken {
121    fn consume<R, F>(self, len: usize, f: F) -> R
122    where
123        F: FnOnce(&mut [u8]) -> R,
124    {
125        let mut lower = self.lower.borrow_mut();
126        let mut buffer = vec![0; len];
127        let result = f(&mut buffer);
128        match lower.send(&buffer[..]) {
129            Ok(_) => {}
130            Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
131                net_debug!("phy: tx failed due to WouldBlock")
132            }
133            Err(err) => panic!("{}", err),
134        }
135        result
136    }
137}