2016-12-11 00:25:43 +08:00
|
|
|
//! Access to networking hardware.
|
|
|
|
//!
|
2016-12-31 20:28:59 +08:00
|
|
|
//! The `phy` module deals with the *network devices*. It provides a trait
|
2017-07-14 11:30:00 +08:00
|
|
|
//! for transmitting and receiving frames, [Device](trait.Device.html)
|
|
|
|
//! and implementations of it:
|
2016-12-31 20:28:59 +08:00
|
|
|
//!
|
2017-07-14 11:30:00 +08:00
|
|
|
//! * the [_loopback_](struct.Loopback.html), for zero dependency testing;
|
|
|
|
//! * _middleware_ [Tracer](struct.Tracer.html) and
|
|
|
|
//! [FaultInjector](struct.FaultInjector.html), to facilitate debugging;
|
|
|
|
//! * _adapters_ [RawSocket](struct.RawSocket.html) and
|
|
|
|
//! [TapInterface](struct.TapInterface.html), to transmit and receive frames
|
|
|
|
//! on the host OS.
|
2016-12-31 20:28:59 +08:00
|
|
|
//!
|
2017-01-01 16:15:38 +08:00
|
|
|
// https://github.com/rust-lang/rust/issues/38740
|
|
|
|
//! <h1 id="examples" class="section-header"><a href="#examples">Examples</a></h1>
|
2016-12-31 20:28:59 +08:00
|
|
|
//!
|
|
|
|
//! An implementation of the [Device](trait.Device.html) trait for a simple hardware
|
|
|
|
//! Ethernet controller could look as follows:
|
|
|
|
//!
|
|
|
|
/*!
|
|
|
|
```rust
|
|
|
|
use std::slice;
|
2017-07-27 21:51:02 +08:00
|
|
|
use smoltcp::{Error, Result};
|
2017-09-16 17:04:07 +08:00
|
|
|
use smoltcp::phy::{DeviceCapabilities, Device};
|
2016-12-31 20:28:59 +08:00
|
|
|
|
|
|
|
const TX_BUFFERS: [*mut u8; 2] = [0x10000000 as *mut u8, 0x10001000 as *mut u8];
|
|
|
|
const RX_BUFFERS: [*mut u8; 2] = [0x10002000 as *mut u8, 0x10003000 as *mut u8];
|
|
|
|
|
|
|
|
fn rx_full() -> bool {
|
|
|
|
/* platform-specific code to check if an incoming packet has arrived */
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2017-06-24 17:01:07 +08:00
|
|
|
fn rx_setup(_buf: *mut u8, _length: &mut usize) {
|
2016-12-31 20:28:59 +08:00
|
|
|
/* platform-specific code to receive a packet into a buffer */
|
|
|
|
}
|
|
|
|
|
|
|
|
fn tx_empty() -> bool {
|
2017-07-23 20:50:26 +08:00
|
|
|
/* platform-specific code to check if an outgoing packet can be sent */
|
2016-12-31 20:28:59 +08:00
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2017-06-24 17:01:07 +08:00
|
|
|
fn tx_setup(_buf: *const u8, _length: usize) {
|
2016-12-31 20:28:59 +08:00
|
|
|
/* platform-specific code to send a buffer with a packet */
|
|
|
|
}
|
|
|
|
|
2017-06-24 17:01:07 +08:00
|
|
|
# #[allow(dead_code)]
|
|
|
|
pub struct EthernetDevice {
|
2017-01-01 16:15:38 +08:00
|
|
|
tx_next: usize,
|
|
|
|
rx_next: usize
|
2016-12-31 20:28:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Device for EthernetDevice {
|
|
|
|
type RxBuffer = &'static [u8];
|
|
|
|
type TxBuffer = EthernetTxBuffer;
|
|
|
|
|
2017-09-16 17:04:07 +08:00
|
|
|
fn capabilities(&self) -> DeviceCapabilities {
|
|
|
|
let mut caps = DeviceCapabilities::default();
|
|
|
|
caps.max_transmission_unit = 1536;
|
|
|
|
caps.max_burst_size = Some(2);
|
|
|
|
caps
|
2017-03-07 18:56:48 +08:00
|
|
|
}
|
2016-12-31 20:28:59 +08:00
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
fn receive(&mut self, _timestamp: u64) -> Result<Self::RxBuffer> {
|
2016-12-31 20:28:59 +08:00
|
|
|
if rx_full() {
|
2017-01-10 20:29:24 +08:00
|
|
|
let index = self.rx_next;
|
2016-12-31 20:28:59 +08:00
|
|
|
self.rx_next = (self.rx_next + 1) % RX_BUFFERS.len();
|
2017-01-10 20:29:24 +08:00
|
|
|
let mut length = 0;
|
|
|
|
rx_setup(RX_BUFFERS[self.rx_next], &mut length);
|
|
|
|
Ok(unsafe {
|
|
|
|
slice::from_raw_parts(RX_BUFFERS[index], length)
|
|
|
|
})
|
2016-12-31 20:28:59 +08:00
|
|
|
} else {
|
|
|
|
Err(Error::Exhausted)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
fn transmit(&mut self, _timestamp: u64, length: usize) -> Result<Self::TxBuffer> {
|
2016-12-31 20:28:59 +08:00
|
|
|
if tx_empty() {
|
|
|
|
let index = self.tx_next;
|
|
|
|
self.tx_next = (self.tx_next + 1) % TX_BUFFERS.len();
|
2017-01-10 20:29:24 +08:00
|
|
|
Ok(EthernetTxBuffer(unsafe {
|
|
|
|
slice::from_raw_parts_mut(TX_BUFFERS[index], length)
|
|
|
|
}))
|
2016-12-31 20:28:59 +08:00
|
|
|
} else {
|
|
|
|
Err(Error::Exhausted)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-24 17:01:07 +08:00
|
|
|
pub struct EthernetTxBuffer(&'static mut [u8]);
|
2016-12-31 20:28:59 +08:00
|
|
|
|
|
|
|
impl AsRef<[u8]> for EthernetTxBuffer {
|
2017-01-01 16:15:38 +08:00
|
|
|
fn as_ref(&self) -> &[u8] { self.0 }
|
2016-12-31 20:28:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AsMut<[u8]> for EthernetTxBuffer {
|
2017-01-01 16:15:38 +08:00
|
|
|
fn as_mut(&mut self) -> &mut [u8] { self.0 }
|
2016-12-31 20:28:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for EthernetTxBuffer {
|
2017-01-10 20:29:24 +08:00
|
|
|
fn drop(&mut self) { tx_setup(self.0.as_ptr(), self.0.len()) }
|
2016-12-31 20:28:59 +08:00
|
|
|
}
|
|
|
|
```
|
|
|
|
*/
|
2016-12-15 01:39:44 +08:00
|
|
|
|
2017-07-30 09:09:14 +08:00
|
|
|
use Result;
|
2016-12-11 07:15:26 +08:00
|
|
|
|
2017-09-25 07:51:19 +08:00
|
|
|
#[cfg(any(feature = "phy-raw_socket", feature = "phy-tap_interface"))]
|
2016-12-11 07:15:26 +08:00
|
|
|
mod sys;
|
2016-12-11 00:25:43 +08:00
|
|
|
|
2016-12-12 20:30:35 +08:00
|
|
|
mod tracer;
|
2016-12-31 09:04:39 +08:00
|
|
|
mod fault_injector;
|
2017-07-23 20:50:26 +08:00
|
|
|
mod pcap_writer;
|
2017-09-23 04:40:13 +08:00
|
|
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
2017-07-14 09:05:05 +08:00
|
|
|
mod loopback;
|
2017-09-25 07:51:19 +08:00
|
|
|
#[cfg(feature = "phy-raw_socket")]
|
2016-12-11 00:25:43 +08:00
|
|
|
mod raw_socket;
|
2017-09-25 07:51:19 +08:00
|
|
|
#[cfg(all(feature = "phy-tap_interface", target_os = "linux"))]
|
2016-12-11 07:15:26 +08:00
|
|
|
mod tap_interface;
|
|
|
|
|
2017-09-25 07:51:19 +08:00
|
|
|
#[cfg(any(feature = "phy-raw_socket", feature = "phy-tap_interface"))]
|
2017-08-30 03:35:09 +08:00
|
|
|
pub use self::sys::wait;
|
|
|
|
|
2016-12-12 20:30:35 +08:00
|
|
|
pub use self::tracer::Tracer;
|
2016-12-31 09:04:39 +08:00
|
|
|
pub use self::fault_injector::FaultInjector;
|
2017-07-23 20:50:26 +08:00
|
|
|
pub use self::pcap_writer::{PcapLinkType, PcapMode, PcapSink, PcapWriter};
|
2017-09-23 04:40:13 +08:00
|
|
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
2017-07-14 09:17:06 +08:00
|
|
|
pub use self::loopback::Loopback;
|
2017-09-25 07:51:19 +08:00
|
|
|
#[cfg(any(feature = "phy-raw_socket"))]
|
2016-12-11 07:15:26 +08:00
|
|
|
pub use self::raw_socket::RawSocket;
|
2017-09-25 07:51:19 +08:00
|
|
|
#[cfg(all(feature = "phy-tap_interface", target_os = "linux"))]
|
2016-12-11 07:15:26 +08:00
|
|
|
pub use self::tap_interface::TapInterface;
|
2016-12-11 00:25:43 +08:00
|
|
|
|
2017-07-23 14:20:38 +08:00
|
|
|
/// A tracer device for Ethernet frames.
|
|
|
|
pub type EthernetTracer<T> = Tracer<T, super::wire::EthernetFrame<&'static [u8]>>;
|
|
|
|
|
2017-10-02 18:47:51 +08:00
|
|
|
/// The checksum configuration for a device
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub enum Checksum {
|
|
|
|
/// Validate checksum when receiving and supply checksum when sending
|
|
|
|
Both,
|
|
|
|
/// Validate checksum when receiving
|
|
|
|
Rx,
|
|
|
|
/// Supply checksum before sending
|
|
|
|
Tx,
|
|
|
|
/// Ignore checksum
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Checksum {
|
|
|
|
fn default() -> Checksum {
|
|
|
|
Checksum::Both
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Checksum {
|
|
|
|
pub(crate) fn rx(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
Checksum::Both | Checksum::Rx => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn tx(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
Checksum::Both | Checksum::Tx => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Configuration of checksum capabilities for each applicable protocol
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
|
|
pub struct ChecksumCapabilities {
|
|
|
|
pub ipv4: Checksum,
|
|
|
|
pub udpv4: Checksum,
|
|
|
|
pub udpv6: Checksum,
|
|
|
|
pub tcpv4: Checksum,
|
|
|
|
pub icmpv4: Checksum,
|
|
|
|
dummy: (),
|
|
|
|
}
|
|
|
|
|
2017-09-16 17:04:07 +08:00
|
|
|
/// A description of device capabilities.
|
2017-03-07 18:56:48 +08:00
|
|
|
///
|
|
|
|
/// Higher-level protocols may achieve higher throughput or lower latency if they consider
|
|
|
|
/// the bandwidth or packet size limitations.
|
|
|
|
#[derive(Debug, Clone, Default)]
|
2017-09-16 17:04:07 +08:00
|
|
|
pub struct DeviceCapabilities {
|
2017-03-07 18:56:48 +08:00
|
|
|
/// Maximum transmission unit.
|
|
|
|
///
|
|
|
|
/// The network device is unable to send or receive frames larger than the value returned
|
|
|
|
/// by this function.
|
|
|
|
///
|
|
|
|
/// For Ethernet, MTU will fall between 576 (for IPv4) or 1280 (for IPv6) and 9216 octets.
|
|
|
|
pub max_transmission_unit: usize,
|
|
|
|
|
|
|
|
/// Maximum burst size, in terms of MTU.
|
|
|
|
///
|
|
|
|
/// The network device is unable to send or receive bursts large than the value returned
|
|
|
|
/// by this function.
|
|
|
|
///
|
|
|
|
/// If `None`, there is no fixed limit on burst size, e.g. if network buffers are
|
|
|
|
/// dynamically allocated.
|
|
|
|
pub max_burst_size: Option<usize>,
|
|
|
|
|
2017-10-02 18:47:51 +08:00
|
|
|
/// Checksum capabilities for the current device
|
|
|
|
pub checksum: ChecksumCapabilities,
|
|
|
|
|
2017-03-07 18:56:48 +08:00
|
|
|
/// Only present to prevent people from trying to initialize every field of DeviceLimits,
|
|
|
|
/// which would not let us add new fields in the future.
|
|
|
|
dummy: ()
|
|
|
|
}
|
|
|
|
|
2016-12-11 03:27:07 +08:00
|
|
|
/// An interface for sending and receiving raw network frames.
|
|
|
|
///
|
|
|
|
/// It is expected that a `Device` implementation would allocate memory for both sending
|
|
|
|
/// and receiving packets from memory pools; hence, the stack borrows the buffer for a packet
|
|
|
|
/// that it is about to receive, as well for a packet that it is about to send, from the device.
|
|
|
|
pub trait Device {
|
2016-12-12 20:30:35 +08:00
|
|
|
type RxBuffer: AsRef<[u8]>;
|
|
|
|
type TxBuffer: AsRef<[u8]> + AsMut<[u8]>;
|
|
|
|
|
2017-09-16 17:04:07 +08:00
|
|
|
/// Get a description of device capabilities.
|
|
|
|
fn capabilities(&self) -> DeviceCapabilities;
|
2016-12-11 03:27:07 +08:00
|
|
|
|
2016-12-12 20:30:35 +08:00
|
|
|
/// Receive a frame.
|
2016-12-11 03:27:07 +08:00
|
|
|
///
|
2016-12-12 20:30:35 +08:00
|
|
|
/// It is expected that a `receive` implementation, once a packet is written to memory
|
2016-12-11 03:27:07 +08:00
|
|
|
/// through DMA, would gain ownership of the underlying buffer, provide it for parsing,
|
2016-12-12 20:30:35 +08:00
|
|
|
/// and return it to the network device once it is dropped.
|
2017-07-27 21:51:02 +08:00
|
|
|
fn receive(&mut self, timestamp: u64) -> Result<Self::RxBuffer>;
|
2016-12-11 03:27:07 +08:00
|
|
|
|
2016-12-12 20:30:35 +08:00
|
|
|
/// Transmit a frame.
|
2016-12-11 03:27:07 +08:00
|
|
|
///
|
2016-12-12 20:30:35 +08:00
|
|
|
/// It is expected that a `transmit` implementation would gain ownership of a buffer with
|
|
|
|
/// the requested length, provide it for emission, and schedule it to be read from
|
|
|
|
/// memory by the network device once it is dropped.
|
2017-07-27 21:51:02 +08:00
|
|
|
fn transmit(&mut self, timestamp: u64, length: usize) -> Result<Self::TxBuffer>;
|
2016-12-11 03:27:07 +08:00
|
|
|
}
|