Skip to main content

xarxa_driver/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3//!
4//! ## Feature flags
5#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
6
7pub mod config;
8
9mod buf;
10mod meta;
11
12#[cfg(feature = "async")]
13use core::task::Waker;
14
15pub use buf::PacketBuf;
16pub use meta::PacketMeta;
17#[cfg(feature = "packetmeta-timestamp")]
18pub use meta::{Timestamp, TxTimestamp};
19
20/// Error returned by an operation the driver does not support.
21#[cfg(feature = "async")]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[derive(Debug, Eq, PartialEq, Copy, Clone)]
24pub struct NotSupported;
25
26/// Link state of a network device.
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28#[derive(Debug, Eq, PartialEq, Copy, Clone)]
29pub enum LinkState {
30    /// The link is down. No frames can pass.
31    Down,
32    /// The link is up.
33    Up,
34}
35
36/// Type of medium of a network device.
37///
38/// This is `#[non_exhaustive]` so that media can be added later without breaking
39/// every driver.
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
41#[derive(Debug, Eq, PartialEq, Copy, Clone)]
42#[non_exhaustive]
43pub enum Medium {
44    /// Ethernet medium. Devices of this type send and receive Ethernet frames.
45    Ethernet,
46
47    /// IP medium. Devices of this type send and receive IP frames, without an
48    /// Ethernet header. MAC addresses are not used.
49    Ip,
50
51    /// IEEE 802.15.4 medium. Devices of this type send and receive 802.15.4
52    /// MAC frames carrying 6LoWPAN.
53    ///
54    /// [`Capabilities::max_transmission_unit`] is the whole MAC frame
55    /// without the FCS: 125 for a 127-byte PHY frame with a 2-byte FCS.
56    Ieee802154,
57}
58
59/// A hardware (link-layer) address, as reported by a driver.
60///
61/// This is `#[non_exhaustive]` so that address kinds can be added later without
62/// breaking every driver.
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65#[non_exhaustive]
66pub enum HardwareAddress {
67    /// An Ethernet (MAC) address.
68    Ethernet([u8; 6]),
69    /// No address, for devices that send and receive bare IP packets.
70    Ip,
71    /// An IEEE 802.15.4 extended (64-bit) address.
72    Ieee802154([u8; 8]),
73}
74
75impl HardwareAddress {
76    /// The medium this kind of address belongs to.
77    pub const fn medium(&self) -> Medium {
78        match self {
79            HardwareAddress::Ethernet(_) => Medium::Ethernet,
80            HardwareAddress::Ip => Medium::Ip,
81            HardwareAddress::Ieee802154(_) => Medium::Ieee802154,
82        }
83    }
84}
85
86/// Checksum offload capabilities for a given protocol, per direction.
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
89pub struct ChecksumOffload {
90    /// The device verifies the checksum of received packets.
91    ///
92    /// The stack then does not verify it in software.
93    pub rx: bool,
94    /// The device fills in the checksum of transmitted packets.
95    ///
96    /// The stack then writes the field as zero instead of computing it.
97    pub tx: bool,
98}
99
100impl ChecksumOffload {
101    /// No offload. The stack computes and verifies the checksum in software.
102    pub const NONE: Self = Self { rx: false, tx: false };
103    /// Offload in both directions.
104    pub const BOTH: Self = Self { rx: true, tx: true };
105}
106
107/// Checksum offload capabilities per protocol direction.
108///
109/// The stack skips the offloaded work in software.
110///
111/// The default is no offload for every protocol: the stack computes and
112/// verifies everything itself.
113///
114/// A checksum the stack does not compute is written as zero, so that a device
115/// that fills it in finds a known value there.
116///
117/// The fields are the protocols with a checksum the stack handles. IGMP is not
118/// among them: its checksum is always computed and verified in software.
119#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
121#[non_exhaustive]
122pub struct ChecksumCapabilities {
123    /// Offload for the IPv4 header checksum.
124    pub ipv4: ChecksumOffload,
125    /// Offload for the UDP checksum.
126    pub udp: ChecksumOffload,
127    /// Offload for the TCP checksum.
128    pub tcp: ChecksumOffload,
129    /// Offload for the ICMPv4 checksum.
130    pub icmpv4: ChecksumOffload,
131    /// Offload for the ICMPv6 checksum.
132    pub icmpv6: ChecksumOffload,
133}
134
135impl ChecksumCapabilities {
136    /// Every checksum offloaded in both directions.
137    ///
138    /// The stack computes and verifies nothing. Use this for devices where
139    /// checksums don't matter, like loopback.
140    pub fn all_offloaded() -> Self {
141        ChecksumCapabilities {
142            ipv4: ChecksumOffload::BOTH,
143            udp: ChecksumOffload::BOTH,
144            tcp: ChecksumOffload::BOTH,
145            icmpv4: ChecksumOffload::BOTH,
146            icmpv6: ChecksumOffload::BOTH,
147        }
148    }
149}
150
151/// A description of a device's capabilities.
152///
153/// This is `#[non_exhaustive]` so that capabilities can be added later without breaking
154/// every driver. Drivers live outside this crate and so cannot use a struct expression,
155/// they start from [`Default`] and overwrite the fields they care about:
156///
157/// ```
158/// # use xarxa_driver::Capabilities;
159/// let mut caps = Capabilities::default();
160/// caps.max_transmission_unit = 1514;
161/// // caps.medium = Medium::Ethernet; is the default
162/// ```
163#[cfg_attr(feature = "defmt", derive(defmt::Format))]
164#[derive(Debug, Clone)]
165#[non_exhaustive]
166pub struct Capabilities {
167    /// Medium of the device.
168    pub medium: Medium,
169
170    /// Maximum transmission unit.
171    ///
172    /// The network device is unable to send or receive frames larger than the value returned
173    /// by this function.
174    pub max_transmission_unit: usize,
175
176    /// Checksum offload.
177    ///
178    /// Which checksums the device's hardware verifies or computes, so the
179    /// stack skips them in software.
180    pub checksum: ChecksumCapabilities,
181}
182
183impl Default for Capabilities {
184    fn default() -> Self {
185        Self {
186            medium: Medium::Ethernet,
187            max_transmission_unit: 1514,
188            checksum: ChecksumCapabilities::default(),
189        }
190    }
191}
192
193/// A network device driver, sending and receiving raw network frames.
194pub trait Driver {
195    /// Get a description of the device's capabilities.
196    fn capabilities(&self) -> Capabilities;
197
198    /// Get the device's hardware address.
199    ///
200    /// The address kind must match the medium in [`capabilities`](Self::capabilities):
201    /// an Ethernet address for [`Medium::Ethernet`], [`HardwareAddress::Ip`] for
202    /// [`Medium::Ip`], an IEEE 802.15.4 extended address for [`Medium::Ieee802154`].
203    ///
204    /// The stack reads it once, when the driver is added to it. The stack has its
205    /// own way to override the address after that.
206    fn hardware_address(&self) -> HardwareAddress;
207
208    /// Get the link state.
209    ///
210    /// Devices that cannot tell, or whose link is always up, return
211    /// [`LinkState::Up`], which is the default implementation.
212    fn link_state(&mut self) -> LinkState {
213        LinkState::Up
214    }
215
216    /// Register a waker.
217    ///
218    /// The driver must wake it when:
219    /// - a frame has been received, so [`receive`](Self::receive) may return `Some`,
220    /// - there is room to transmit again, after [`can_transmit`](Self::can_transmit) returned `false`,
221    /// - the link state changed, so [`link_state`](Self::link_state) may return something new.
222    ///
223    /// Only one waker is kept. Registering another replaces it. Wakes are
224    /// allowed to be spurious.
225    ///
226    /// A registered waker is woken just one. The main loop must re-register it if
227    /// it wants to be woken again.
228    ///
229    /// Drivers that cannot wake anything return `Err(NotSupported)`, which is the
230    /// default implementation. Such a driver can only be polled, so a caller that
231    /// needs to sleep until the driver has something new cannot use it.
232    #[cfg(feature = "async")]
233    fn register_waker(&mut self, waker: &Waker) -> Result<(), NotSupported> {
234        let _ = waker;
235        Err(NotSupported)
236    }
237
238    /// Poll for a received frame.
239    ///
240    /// Returns a buffer holding the received frame if one is available, transferring
241    /// ownership of it to the caller.
242    ///
243    /// A driver that has per-packet metadata to report, such as an identifier or a
244    /// receive timestamp, sets it on the buffer's [`PacketMeta`] here. It travels
245    /// with the packet up to the socket that receives it.
246    fn receive(&mut self) -> Option<PacketBuf>;
247
248    /// Whether the device can transmit one frame right now.
249    ///
250    /// Devices typically have a transmit packet queue. This returns
251    /// whether this queue has space to take one more frame.
252    ///
253    /// If this returns `true`, the next `transmit()` call must not fail.
254    ///
255    /// In devices where there's no queue so transmit always succeeds, this
256    /// should always return `true`.
257    fn can_transmit(&mut self) -> bool;
258
259    /// Queue a frame for transmission, transferring ownership of the buffer to the driver.
260    ///
261    /// The driver holds the buffer until the hardware is done with it, then drops it.
262    /// If the frame cannot be queued right now (device busy or queue full), the buffer
263    /// is handed back in the `Err` variant.
264    ///
265    /// The buffer's [`PacketMeta`] is whatever the sending socket attached to the
266    /// packet (default for packets the stack generates itself). A driver that
267    /// supports transmit timestamping timestamps the frame if
268    /// [`request_timestamp`](PacketMeta::request_timestamp) is set, and reports
269    /// the result from [`poll_tx_timestamp`](Self::poll_tx_timestamp) tagged with the
270    /// packet's [`id`](PacketMeta::id).
271    fn transmit(&mut self, buf: PacketBuf) -> Result<(), PacketBuf>;
272
273    /// Poll for the timestamp of an already-transmitted packet.
274    ///
275    /// Returns the transmit timestamp of a packet previously sent with
276    /// [`PacketMeta::request_timestamp`] set, tagged with that packet's
277    /// [`PacketMeta::id`], or `None` if no timestamp is available right now.
278    ///
279    /// Transmit timestamps are reported out of band, rather than on the packet like
280    /// receive timestamps are, because a packet's transmit timestamp does not exist yet
281    /// when [`transmit`](Self::transmit) returns: it has not gone out on the wire yet.
282    ///
283    /// Callers must be robust against all of the following:
284    ///
285    /// * Timestamps become available an arbitrary time after `transmit` returned, so
286    ///   this should be polled repeatedly, not just once after sending.
287    /// * Timestamps may be reported out of order with respect to transmission.
288    /// * Timestamps may never arrive at all, e.g. because the hardware ran out of
289    ///   timestamp slots. Never block waiting for a particular `id` to show up without
290    ///   a timeout.
291    ///
292    /// Devices that do not support transmit timestamping always return `None`, which is
293    /// the default implementation.
294    #[cfg(feature = "packetmeta-timestamp")]
295    fn poll_tx_timestamp(&mut self) -> Option<TxTimestamp> {
296        None
297    }
298
299    /// Set the device's multicast hardware address filter.
300    ///
301    /// `addrs` is the full list of multicast MAC addresses to listen on. It
302    /// replaces the previous one.
303    ///
304    /// A device with no multicast filter can ignore the calls, which
305    /// is the default implementation.
306    ///
307    /// Only called for [`Medium::Ethernet`] devices. The list has no duplicates.
308    ///
309    /// It may be the same list as last time: the stack does not compare. If
310    /// applying the filter is expensive, the driver should should keep the last
311    /// list and skip if there were no changes.
312    ///
313    /// If the list does not fit the filter, receive the addresses anyway if
314    /// possible, for example by turning the filter off or switching it to
315    /// receive all multicast. Losing filter efficiency is fine, filtering out
316    /// traffic the network stack wants is not.
317    fn set_multicast_filter(&mut self, addrs: &[[u8; 6]]) {
318        let _ = addrs;
319    }
320}
321
322impl<T: Driver + ?Sized> Driver for &mut T {
323    fn capabilities(&self) -> Capabilities {
324        T::capabilities(self)
325    }
326    fn hardware_address(&self) -> HardwareAddress {
327        T::hardware_address(self)
328    }
329    fn link_state(&mut self) -> LinkState {
330        T::link_state(self)
331    }
332    #[cfg(feature = "async")]
333    fn register_waker(&mut self, waker: &Waker) -> Result<(), NotSupported> {
334        T::register_waker(self, waker)
335    }
336    fn receive(&mut self) -> Option<PacketBuf> {
337        T::receive(self)
338    }
339    fn can_transmit(&mut self) -> bool {
340        T::can_transmit(self)
341    }
342    fn transmit(&mut self, buf: PacketBuf) -> Result<(), PacketBuf> {
343        T::transmit(self, buf)
344    }
345    #[cfg(feature = "packetmeta-timestamp")]
346    fn poll_tx_timestamp(&mut self) -> Option<TxTimestamp> {
347        T::poll_tx_timestamp(self)
348    }
349    fn set_multicast_filter(&mut self, addrs: &[[u8; 6]]) {
350        T::set_multicast_filter(self, addrs)
351    }
352}