1 /*! Access to networking hardware.
2 
3 The `phy` module deals with the *network devices*. It provides a trait
4 for transmitting and receiving frames, [Device](trait.Device.html)
5 and implementations of it:
6 
7   * the [_loopback_](struct.Loopback.html), for zero dependency testing;
8   * _middleware_ [Tracer](struct.Tracer.html) and
9     [FaultInjector](struct.FaultInjector.html), to facilitate debugging;
10   * _adapters_ [RawSocket](struct.RawSocket.html) and
11     [TunTapInterface](struct.TunTapInterface.html), to transmit and receive frames
12     on the host OS.
13 */
14 #![cfg_attr(
15     feature = "medium-ethernet",
16     doc = r##"
17 # Examples
18 
19 An implementation of the [Device](trait.Device.html) trait for a simple hardware
20 Ethernet controller could look as follows:
21 
22 ```rust
23 use smoltcp::phy::{self, DeviceCapabilities, Device, Medium};
24 use smoltcp::time::Instant;
25 
26 struct StmPhy {
27     rx_buffer: [u8; 1536],
28     tx_buffer: [u8; 1536],
29 }
30 
31 impl<'a> StmPhy {
32     fn new() -> StmPhy {
33         StmPhy {
34             rx_buffer: [0; 1536],
35             tx_buffer: [0; 1536],
36         }
37     }
38 }
39 
40 impl phy::Device for StmPhy {
41     type RxToken<'a> = StmPhyRxToken<'a> where Self: 'a;
42     type TxToken<'a> = StmPhyTxToken<'a> where Self: 'a;
43 
44     fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
45         Some((StmPhyRxToken(&mut self.rx_buffer[..]),
46               StmPhyTxToken(&mut self.tx_buffer[..])))
47     }
48 
49     fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
50         Some(StmPhyTxToken(&mut self.tx_buffer[..]))
51     }
52 
53     fn capabilities(&self) -> DeviceCapabilities {
54         let mut caps = DeviceCapabilities::default();
55         caps.max_transmission_unit = 1536;
56         caps.max_burst_size = Some(1);
57         caps.medium = Medium::Ethernet;
58         caps
59     }
60 }
61 
62 struct StmPhyRxToken<'a>(&'a mut [u8]);
63 
64 impl<'a> phy::RxToken for StmPhyRxToken<'a> {
65     fn consume<R, F>(mut self, f: F) -> R
66         where F: FnOnce(&mut [u8]) -> R
67     {
68         // TODO: receive packet into buffer
69         let result = f(&mut self.0);
70         println!("rx called");
71         result
72     }
73 }
74 
75 struct StmPhyTxToken<'a>(&'a mut [u8]);
76 
77 impl<'a> phy::TxToken for StmPhyTxToken<'a> {
78     fn consume<R, F>(self, len: usize, f: F) -> R
79         where F: FnOnce(&mut [u8]) -> R
80     {
81         let result = f(&mut self.0[..len]);
82         println!("tx called {}", len);
83         // TODO: send packet out
84         result
85     }
86 }
87 ```
88 "##
89 )]
90 
91 use crate::time::Instant;
92 
93 #[cfg(all(
94     any(feature = "phy-raw_socket", feature = "phy-tuntap_interface"),
95     unix
96 ))]
97 mod sys;
98 
99 mod fault_injector;
100 mod fuzz_injector;
101 #[cfg(feature = "alloc")]
102 mod loopback;
103 mod pcap_writer;
104 #[cfg(all(feature = "phy-raw_socket", unix))]
105 mod raw_socket;
106 mod tracer;
107 #[cfg(all(
108     feature = "phy-tuntap_interface",
109     any(target_os = "linux", target_os = "android")
110 ))]
111 mod tuntap_interface;
112 
113 #[cfg(all(
114     any(feature = "phy-raw_socket", feature = "phy-tuntap_interface"),
115     unix
116 ))]
117 pub use self::sys::wait;
118 
119 pub use self::fault_injector::FaultInjector;
120 pub use self::fuzz_injector::{FuzzInjector, Fuzzer};
121 #[cfg(feature = "alloc")]
122 pub use self::loopback::Loopback;
123 pub use self::pcap_writer::{PcapLinkType, PcapMode, PcapSink, PcapWriter};
124 #[cfg(all(feature = "phy-raw_socket", unix))]
125 pub use self::raw_socket::RawSocket;
126 pub use self::tracer::Tracer;
127 #[cfg(all(
128     feature = "phy-tuntap_interface",
129     any(target_os = "linux", target_os = "android")
130 ))]
131 pub use self::tuntap_interface::TunTapInterface;
132 
133 /// A description of checksum behavior for a particular protocol.
134 #[derive(Debug, Clone, Copy, Default)]
135 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
136 pub enum Checksum {
137     /// Verify checksum when receiving and compute checksum when sending.
138     #[default]
139     Both,
140     /// Verify checksum when receiving.
141     Rx,
142     /// Compute checksum before sending.
143     Tx,
144     /// Ignore checksum completely.
145     None,
146 }
147 
148 impl Checksum {
149     /// Returns whether checksum should be verified when receiving.
rx(&self) -> bool150     pub fn rx(&self) -> bool {
151         match *self {
152             Checksum::Both | Checksum::Rx => true,
153             _ => false,
154         }
155     }
156 
157     /// Returns whether checksum should be verified when sending.
tx(&self) -> bool158     pub fn tx(&self) -> bool {
159         match *self {
160             Checksum::Both | Checksum::Tx => true,
161             _ => false,
162         }
163     }
164 }
165 
166 /// A description of checksum behavior for every supported protocol.
167 #[derive(Debug, Clone, Default)]
168 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
169 #[non_exhaustive]
170 pub struct ChecksumCapabilities {
171     pub ipv4: Checksum,
172     pub udp: Checksum,
173     pub tcp: Checksum,
174     #[cfg(feature = "proto-ipv4")]
175     pub icmpv4: Checksum,
176     #[cfg(feature = "proto-ipv6")]
177     pub icmpv6: Checksum,
178 }
179 
180 impl ChecksumCapabilities {
181     /// Checksum behavior that results in not computing or verifying checksums
182     /// for any of the supported protocols.
ignored() -> Self183     pub fn ignored() -> Self {
184         ChecksumCapabilities {
185             ipv4: Checksum::None,
186             udp: Checksum::None,
187             tcp: Checksum::None,
188             #[cfg(feature = "proto-ipv4")]
189             icmpv4: Checksum::None,
190             #[cfg(feature = "proto-ipv6")]
191             icmpv6: Checksum::None,
192         }
193     }
194 }
195 
196 /// A description of device capabilities.
197 ///
198 /// Higher-level protocols may achieve higher throughput or lower latency if they consider
199 /// the bandwidth or packet size limitations.
200 #[derive(Debug, Clone, Default)]
201 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
202 #[non_exhaustive]
203 pub struct DeviceCapabilities {
204     /// Medium of the device.
205     ///
206     /// This indicates what kind of packet the sent/received bytes are, and determines
207     /// some behaviors of Interface. For example, ARP/NDISC address resolution is only done
208     /// for Ethernet mediums.
209     pub medium: Medium,
210 
211     /// Maximum transmission unit.
212     ///
213     /// The network device is unable to send or receive frames larger than the value returned
214     /// by this function.
215     ///
216     /// For Ethernet devices, this is the maximum Ethernet frame size, including the Ethernet header (14 octets), but
217     /// *not* including the Ethernet FCS (4 octets). Therefore, Ethernet MTU = IP MTU + 14.
218     ///
219     /// Note that in Linux and other OSes, "MTU" is the IP MTU, not the Ethernet MTU, even for Ethernet
220     /// devices. This is a common source of confusion.
221     ///
222     /// Most common IP MTU is 1500. Minimum is 576 (for IPv4) or 1280 (for IPv6). Maximum is 9216 octets.
223     pub max_transmission_unit: usize,
224 
225     /// Maximum burst size, in terms of MTU.
226     ///
227     /// The network device is unable to send or receive bursts large than the value returned
228     /// by this function.
229     ///
230     /// If `None`, there is no fixed limit on burst size, e.g. if network buffers are
231     /// dynamically allocated.
232     pub max_burst_size: Option<usize>,
233 
234     /// Checksum behavior.
235     ///
236     /// If the network device is capable of verifying or computing checksums for some protocols,
237     /// it can request that the stack not do so in software to improve performance.
238     pub checksum: ChecksumCapabilities,
239 }
240 
241 impl DeviceCapabilities {
ip_mtu(&self) -> usize242     pub fn ip_mtu(&self) -> usize {
243         match self.medium {
244             #[cfg(feature = "medium-ethernet")]
245             Medium::Ethernet => {
246                 self.max_transmission_unit - crate::wire::EthernetFrame::<&[u8]>::header_len()
247             }
248             #[cfg(feature = "medium-ip")]
249             Medium::Ip => self.max_transmission_unit,
250             #[cfg(feature = "medium-ieee802154")]
251             Medium::Ieee802154 => self.max_transmission_unit, // TODO(thvdveld): what is the MTU for Medium::IEEE802
252         }
253     }
254 }
255 
256 /// Type of medium of a device.
257 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
258 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
259 pub enum Medium {
260     /// Ethernet medium. Devices of this type send and receive Ethernet frames,
261     /// and interfaces using it must do neighbor discovery via ARP or NDISC.
262     ///
263     /// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode.
264     #[cfg(feature = "medium-ethernet")]
265     Ethernet,
266 
267     /// IP medium. Devices of this type send and receive IP frames, without an
268     /// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done.
269     ///
270     /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
271     #[cfg(feature = "medium-ip")]
272     Ip,
273 
274     #[cfg(feature = "medium-ieee802154")]
275     Ieee802154,
276 }
277 
278 impl Default for Medium {
default() -> Medium279     fn default() -> Medium {
280         #[cfg(feature = "medium-ethernet")]
281         return Medium::Ethernet;
282         #[cfg(all(feature = "medium-ip", not(feature = "medium-ethernet")))]
283         return Medium::Ip;
284         #[cfg(all(
285             feature = "medium-ieee802154",
286             not(feature = "medium-ip"),
287             not(feature = "medium-ethernet")
288         ))]
289         return Medium::Ieee802154;
290         #[cfg(all(
291             not(feature = "medium-ip"),
292             not(feature = "medium-ethernet"),
293             not(feature = "medium-ieee802154")
294         ))]
295         return panic!("No medium enabled");
296     }
297 }
298 
299 /// An interface for sending and receiving raw network frames.
300 ///
301 /// The interface is based on _tokens_, which are types that allow to receive/transmit a
302 /// single packet. The `receive` and `transmit` functions only construct such tokens, the
303 /// real sending/receiving operation are performed when the tokens are consumed.
304 pub trait Device {
305     type RxToken<'a>: RxToken
306     where
307         Self: 'a;
308     type TxToken<'a>: TxToken
309     where
310         Self: 'a;
311 
312     /// Construct a token pair consisting of one receive token and one transmit token.
313     ///
314     /// The additional transmit token makes it possible to generate a reply packet based
315     /// on the contents of the received packet. For example, this makes it possible to
316     /// handle arbitrarily large ICMP echo ("ping") requests, where the all received bytes
317     /// need to be sent back, without heap allocation.
318     ///
319     /// The timestamp must be a number of milliseconds, monotonically increasing since an
320     /// arbitrary moment in time, such as system startup.
receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>321     fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>;
322 
323     /// Construct a transmit token.
324     ///
325     /// The timestamp must be a number of milliseconds, monotonically increasing since an
326     /// arbitrary moment in time, such as system startup.
transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>>327     fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>>;
328 
329     /// Get a description of device capabilities.
capabilities(&self) -> DeviceCapabilities330     fn capabilities(&self) -> DeviceCapabilities;
331 }
332 
333 /// A token to receive a single network packet.
334 pub trait RxToken {
335     /// Consumes the token to receive a single network packet.
336     ///
337     /// This method receives a packet and then calls the given closure `f` with the raw
338     /// packet bytes as argument.
consume<R, F>(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R339     fn consume<R, F>(self, f: F) -> R
340     where
341         F: FnOnce(&mut [u8]) -> R;
342 }
343 
344 /// A token to transmit a single network packet.
345 pub trait TxToken {
346     /// Consumes the token to send a single network packet.
347     ///
348     /// This method constructs a transmit buffer of size `len` and calls the passed
349     /// closure `f` with a mutable reference to that buffer. The closure should construct
350     /// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure
351     /// returns, the transmit buffer is sent out.
consume<R, F>(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R352     fn consume<R, F>(self, len: usize, f: F) -> R
353     where
354         F: FnOnce(&mut [u8]) -> R;
355 }
356