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}