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