#![no_std] #![warn(missing_docs)] #![doc = include_str!("../README.md")] use core::task::Context; /// Representation of an hardware address, such as an Ethernet address or an IEEE802.15.4 address. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum HardwareAddress { /// Ethernet medium, with a A six-octet Ethernet address. /// /// Devices of this type send and receive Ethernet frames, /// and interfaces using it must do neighbor discovery via ARP or NDISC. /// /// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode. Ethernet([u8; 6]), /// 6LoWPAN over IEEE802.15.4, with an eight-octet address. Ieee802154([u8; 8]), /// Indicates that a Driver is IP-native, and has no hardware address. /// /// Devices of this type send and receive IP frames, without an /// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done. /// /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode. Ip, } /// Main `embassy-net` driver API. /// /// This is essentially an interface for sending and receiving raw network frames. /// /// The interface is based on _tokens_, which are types that allow to receive/transmit a /// single packet. The `receive` and `transmit` functions only construct such tokens, the /// real sending/receiving operation are performed when the tokens are consumed. pub trait Driver { /// A token to receive a single network packet. type RxToken<'a>: RxToken where Self: 'a; /// A token to transmit a single network packet. type TxToken<'a>: TxToken where Self: 'a; /// Construct a token pair consisting of one receive token and one transmit token. /// /// If there is a packet ready to be received, this function must return `Some`. /// If there isn't, it must return `None`, and wake `cx.waker()` when a packet is ready. /// /// The additional transmit token makes it possible to generate a reply packet based /// on the contents of the received packet. For example, this makes it possible to /// handle arbitrarily large ICMP echo ("ping") requests, where the all received bytes /// need to be sent back, without heap allocation. fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>; /// Construct a transmit token. /// /// If there is free space in the transmit buffer to transmit a packet, this function must return `Some`. /// If there isn't, it must return `None`, and wake `cx.waker()` when space becomes available. /// /// Note that [`TxToken::consume`] is infallible, so it is not allowed to return a token /// if there is no free space and fail later. fn transmit(&mut self, cx: &mut Context) -> Option>; /// Get the link state. /// /// This function must return the current link state of the device, and wake `cx.waker()` when /// the link state changes. fn link_state(&mut self, cx: &mut Context) -> LinkState; /// Get a description of device capabilities. fn capabilities(&self) -> Capabilities; /// Get the device's hardware address. /// /// The returned hardware address also determines the "medium" of this driver. This indicates /// what kind of packet the sent/received bytes are, and determines some behaviors of /// the interface. For example, ARP/NDISC address resolution is only done for Ethernet mediums. fn hardware_address(&self) -> HardwareAddress; } impl Driver for &mut T { type RxToken<'a> = T::RxToken<'a> where Self: 'a; type TxToken<'a> = T::TxToken<'a> where Self: 'a; fn transmit(&mut self, cx: &mut Context) -> Option> { T::transmit(self, cx) } fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { T::receive(self, cx) } fn capabilities(&self) -> Capabilities { T::capabilities(self) } fn link_state(&mut self, cx: &mut Context) -> LinkState { T::link_state(self, cx) } fn hardware_address(&self) -> HardwareAddress { T::hardware_address(self) } } /// A token to receive a single network packet. pub trait RxToken { /// Consumes the token to receive a single network packet. /// /// This method receives a packet and then calls the given closure `f` with the raw /// packet bytes as argument. fn consume(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R; } /// A token to transmit a single network packet. pub trait TxToken { /// Consumes the token to send a single network packet. /// /// This method constructs a transmit buffer of size `len` and calls the passed /// closure `f` with a mutable reference to that buffer. The closure should construct /// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure /// returns, the transmit buffer is sent out. fn consume(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R; } /// A description of device capabilities. /// /// Higher-level protocols may achieve higher throughput or lower latency if they consider /// the bandwidth or packet size limitations. #[derive(Debug, Clone, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct Capabilities { /// Maximum transmission unit. /// /// The network device is unable to send or receive frames larger than the value returned /// by this function. /// /// For Ethernet devices, this is the maximum Ethernet frame size, including the Ethernet header (14 octets), but /// *not* including the Ethernet FCS (4 octets). Therefore, Ethernet MTU = IP MTU + 14. /// /// Note that in Linux and other OSes, "MTU" is the IP MTU, not the Ethernet MTU, even for Ethernet /// devices. This is a common source of confusion. /// /// Most common IP MTU is 1500. Minimum is 576 (for IPv4) or 1280 (for IPv6). Maximum is 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, /// Checksum behavior. /// /// If the network device is capable of verifying or computing checksums for some protocols, /// it can request that the stack not do so in software to improve performance. pub checksum: ChecksumCapabilities, } /// A description of checksum behavior for every supported protocol. #[derive(Debug, Clone, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct ChecksumCapabilities { /// Checksum behavior for IPv4. pub ipv4: Checksum, /// Checksum behavior for UDP. pub udp: Checksum, /// Checksum behavior for TCP. pub tcp: Checksum, /// Checksum behavior for ICMPv4. pub icmpv4: Checksum, /// Checksum behavior for ICMPv6. pub icmpv6: Checksum, } /// A description of checksum behavior for a particular protocol. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Checksum { /// Verify checksum when receiving and compute checksum when sending. Both, /// Verify checksum when receiving. Rx, /// Compute checksum before sending. Tx, /// Ignore checksum completely. None, } impl Default for Checksum { fn default() -> Checksum { Checksum::Both } } /// The link state of a network device. #[derive(PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum LinkState { /// The link is down. Down, /// The link is up. Up, }