mod.rs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*! Access to networking hardware.
  2. The `phy` module deals with the *network devices*. It provides a trait
  3. for transmitting and receiving frames, [Device](trait.Device.html)
  4. and implementations of it:
  5. * the [_loopback_](struct.Loopback.html), for zero dependency testing;
  6. * _middleware_ [Tracer](struct.Tracer.html) and
  7. [FaultInjector](struct.FaultInjector.html), to facilitate debugging;
  8. * _adapters_ [RawSocket](struct.RawSocket.html) and
  9. [TapInterface](struct.TapInterface.html), to transmit and receive frames
  10. on the host OS.
  11. # Examples
  12. An implementation of the [Device](trait.Device.html) trait for a simple hardware
  13. Ethernet controller could look as follows:
  14. ```rust
  15. use smoltcp::Result;
  16. use smoltcp::phy::{self, DeviceCapabilities, Device};
  17. use smoltcp::time::Instant;
  18. struct StmPhy {
  19. rx_buffer: [u8; 1536],
  20. tx_buffer: [u8; 1536],
  21. }
  22. impl<'a> StmPhy {
  23. fn new() -> StmPhy {
  24. StmPhy {
  25. rx_buffer: [0; 1536],
  26. tx_buffer: [0; 1536],
  27. }
  28. }
  29. }
  30. impl<'a> phy::Device<'a> for StmPhy {
  31. type RxToken = StmPhyRxToken<'a>;
  32. type TxToken = StmPhyTxToken<'a>;
  33. fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
  34. Some((StmPhyRxToken(&mut self.rx_buffer[..]),
  35. StmPhyTxToken(&mut self.tx_buffer[..])))
  36. }
  37. fn transmit(&'a mut self) -> Option<Self::TxToken> {
  38. Some(StmPhyTxToken(&mut self.tx_buffer[..]))
  39. }
  40. fn capabilities(&self) -> DeviceCapabilities {
  41. let mut caps = DeviceCapabilities::default();
  42. caps.max_transmission_unit = 1536;
  43. caps.max_burst_size = Some(1);
  44. caps
  45. }
  46. }
  47. struct StmPhyRxToken<'a>(&'a mut [u8]);
  48. impl<'a> phy::RxToken for StmPhyRxToken<'a> {
  49. fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> Result<R>
  50. where F: FnOnce(&mut [u8]) -> Result<R>
  51. {
  52. // TODO: receive packet into buffer
  53. let result = f(&mut self.0);
  54. println!("rx called");
  55. result
  56. }
  57. }
  58. struct StmPhyTxToken<'a>(&'a mut [u8]);
  59. impl<'a> phy::TxToken for StmPhyTxToken<'a> {
  60. fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
  61. where F: FnOnce(&mut [u8]) -> Result<R>
  62. {
  63. let result = f(&mut self.0[..len]);
  64. println!("tx called {}", len);
  65. // TODO: send packet out
  66. result
  67. }
  68. }
  69. ```
  70. */
  71. use crate::Result;
  72. use crate::time::Instant;
  73. #[cfg(all(any(feature = "phy-raw_socket", feature = "phy-tap_interface"), unix))]
  74. mod sys;
  75. mod tracer;
  76. mod fault_injector;
  77. mod fuzz_injector;
  78. mod pcap_writer;
  79. #[cfg(any(feature = "std", feature = "alloc"))]
  80. mod loopback;
  81. #[cfg(all(feature = "phy-raw_socket", unix))]
  82. mod raw_socket;
  83. #[cfg(all(feature = "phy-tap_interface", target_os = "linux"))]
  84. mod tap_interface;
  85. #[cfg(all(any(feature = "phy-raw_socket", feature = "phy-tap_interface"), unix))]
  86. pub use self::sys::wait;
  87. pub use self::tracer::Tracer;
  88. pub use self::fault_injector::FaultInjector;
  89. pub use self::fuzz_injector::{Fuzzer, FuzzInjector};
  90. pub use self::pcap_writer::{PcapLinkType, PcapMode, PcapSink, PcapWriter};
  91. #[cfg(any(feature = "std", feature = "alloc"))]
  92. pub use self::loopback::Loopback;
  93. #[cfg(all(feature = "phy-raw_socket", unix))]
  94. pub use self::raw_socket::RawSocket;
  95. #[cfg(all(feature = "phy-tap_interface", target_os = "linux"))]
  96. pub use self::tap_interface::TapInterface;
  97. #[cfg(feature = "ethernet")]
  98. /// A tracer device for Ethernet frames.
  99. pub type EthernetTracer<T> = Tracer<T, super::wire::EthernetFrame<&'static [u8]>>;
  100. /// A description of checksum behavior for a particular protocol.
  101. #[derive(Debug, Clone, Copy)]
  102. pub enum Checksum {
  103. /// Verify checksum when receiving and compute checksum when sending.
  104. Both,
  105. /// Verify checksum when receiving.
  106. Rx,
  107. /// Compute checksum before sending.
  108. Tx,
  109. /// Ignore checksum completely.
  110. None,
  111. }
  112. impl Default for Checksum {
  113. fn default() -> Checksum {
  114. Checksum::Both
  115. }
  116. }
  117. impl Checksum {
  118. /// Returns whether checksum should be verified when receiving.
  119. pub fn rx(&self) -> bool {
  120. match *self {
  121. Checksum::Both | Checksum::Rx => true,
  122. _ => false
  123. }
  124. }
  125. /// Returns whether checksum should be verified when sending.
  126. pub fn tx(&self) -> bool {
  127. match *self {
  128. Checksum::Both | Checksum::Tx => true,
  129. _ => false
  130. }
  131. }
  132. }
  133. /// A description of checksum behavior for every supported protocol.
  134. #[derive(Debug, Clone, Default)]
  135. pub struct ChecksumCapabilities {
  136. pub ipv4: Checksum,
  137. pub udp: Checksum,
  138. pub tcp: Checksum,
  139. #[cfg(feature = "proto-ipv4")]
  140. pub icmpv4: Checksum,
  141. #[cfg(feature = "proto-ipv6")]
  142. pub icmpv6: Checksum,
  143. dummy: (),
  144. }
  145. impl ChecksumCapabilities {
  146. /// Checksum behavior that results in not computing or verifying checksums
  147. /// for any of the supported protocols.
  148. pub fn ignored() -> Self {
  149. ChecksumCapabilities {
  150. ipv4: Checksum::None,
  151. udp: Checksum::None,
  152. tcp: Checksum::None,
  153. #[cfg(feature = "proto-ipv4")]
  154. icmpv4: Checksum::None,
  155. #[cfg(feature = "proto-ipv6")]
  156. icmpv6: Checksum::None,
  157. ..Self::default()
  158. }
  159. }
  160. }
  161. /// A description of device capabilities.
  162. ///
  163. /// Higher-level protocols may achieve higher throughput or lower latency if they consider
  164. /// the bandwidth or packet size limitations.
  165. #[derive(Debug, Clone, Default)]
  166. pub struct DeviceCapabilities {
  167. /// Maximum transmission unit.
  168. ///
  169. /// The network device is unable to send or receive frames larger than the value returned
  170. /// by this function.
  171. ///
  172. /// For Ethernet, MTU will fall between 576 (for IPv4) or 1280 (for IPv6) and 9216 octets.
  173. pub max_transmission_unit: usize,
  174. /// Maximum burst size, in terms of MTU.
  175. ///
  176. /// The network device is unable to send or receive bursts large than the value returned
  177. /// by this function.
  178. ///
  179. /// If `None`, there is no fixed limit on burst size, e.g. if network buffers are
  180. /// dynamically allocated.
  181. pub max_burst_size: Option<usize>,
  182. /// Checksum behavior.
  183. ///
  184. /// If the network device is capable of verifying or computing checksums for some protocols,
  185. /// it can request that the stack not do so in software to improve performance.
  186. pub checksum: ChecksumCapabilities,
  187. /// Only present to prevent people from trying to initialize every field of DeviceLimits,
  188. /// which would not let us add new fields in the future.
  189. dummy: ()
  190. }
  191. /// An interface for sending and receiving raw network frames.
  192. ///
  193. /// The interface is based on _tokens_, which are types that allow to receive/transmit a
  194. /// single packet. The `receive` and `transmit` functions only construct such tokens, the
  195. /// real sending/receiving operation are performed when the tokens are consumed.
  196. pub trait Device<'a> {
  197. type RxToken: RxToken + 'a;
  198. type TxToken: TxToken + 'a;
  199. /// Construct a token pair consisting of one receive token and one transmit token.
  200. ///
  201. /// The additional transmit token makes it possible to generate a reply packet based
  202. /// on the contents of the received packet. For example, this makes it possible to
  203. /// handle arbitrarily large ICMP echo ("ping") requests, where the all received bytes
  204. /// need to be sent back, without heap allocation.
  205. fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)>;
  206. /// Construct a transmit token.
  207. fn transmit(&'a mut self) -> Option<Self::TxToken>;
  208. /// Get a description of device capabilities.
  209. fn capabilities(&self) -> DeviceCapabilities;
  210. }
  211. /// A token to receive a single network packet.
  212. pub trait RxToken {
  213. /// Consumes the token to receive a single network packet.
  214. ///
  215. /// This method receives a packet and then calls the given closure `f` with the raw
  216. /// packet bytes as argument.
  217. ///
  218. /// The timestamp must be a number of milliseconds, monotonically increasing since an
  219. /// arbitrary moment in time, such as system startup.
  220. fn consume<R, F>(self, timestamp: Instant, f: F) -> Result<R>
  221. where F: FnOnce(&mut [u8]) -> Result<R>;
  222. }
  223. /// A token to transmit a single network packet.
  224. pub trait TxToken {
  225. /// Consumes the token to send a single network packet.
  226. ///
  227. /// This method constructs a transmit buffer of size `len` and calls the passed
  228. /// closure `f` with a mutable reference to that buffer. The closure should construct
  229. /// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure
  230. /// returns, the transmit buffer is sent out.
  231. ///
  232. /// The timestamp must be a number of milliseconds, monotonically increasing since an
  233. /// arbitrary moment in time, such as system startup.
  234. fn consume<R, F>(self, timestamp: Instant, len: usize, f: F) -> Result<R>
  235. where F: FnOnce(&mut [u8]) -> Result<R>;
  236. }