1 | #![no_std ] |
2 | #![warn (missing_docs)] |
3 | #![doc = include_str!("../README.md" )] |
4 | |
5 | use core::task::Context; |
6 | |
7 | /// Representation of an hardware address, such as an Ethernet address or an IEEE802.15.4 address. |
8 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
9 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
10 | #[non_exhaustive ] |
11 | pub enum HardwareAddress { |
12 | /// Ethernet medium, with a A six-octet Ethernet address. |
13 | /// |
14 | /// Devices of this type send and receive Ethernet frames, |
15 | /// and interfaces using it must do neighbor discovery via ARP or NDISC. |
16 | /// |
17 | /// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode. |
18 | Ethernet([u8; 6]), |
19 | /// 6LoWPAN over IEEE802.15.4, with an eight-octet address. |
20 | Ieee802154([u8; 8]), |
21 | /// Indicates that a Driver is IP-native, and has no hardware address. |
22 | /// |
23 | /// Devices of this type send and receive IP frames, without an |
24 | /// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done. |
25 | /// |
26 | /// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode. |
27 | Ip, |
28 | } |
29 | |
30 | /// Main `embassy-net` driver API. |
31 | /// |
32 | /// This is essentially an interface for sending and receiving raw network frames. |
33 | /// |
34 | /// The interface is based on _tokens_, which are types that allow to receive/transmit a |
35 | /// single packet. The `receive` and `transmit` functions only construct such tokens, the |
36 | /// real sending/receiving operation are performed when the tokens are consumed. |
37 | pub trait Driver { |
38 | /// A token to receive a single network packet. |
39 | type RxToken<'a>: RxToken |
40 | where |
41 | Self: 'a; |
42 | |
43 | /// A token to transmit a single network packet. |
44 | type TxToken<'a>: TxToken |
45 | where |
46 | Self: 'a; |
47 | |
48 | /// Construct a token pair consisting of one receive token and one transmit token. |
49 | /// |
50 | /// If there is a packet ready to be received, this function must return `Some`. |
51 | /// If there isn't, it must return `None`, and wake `cx.waker()` when a packet is ready. |
52 | /// |
53 | /// The additional transmit token makes it possible to generate a reply packet based |
54 | /// on the contents of the received packet. For example, this makes it possible to |
55 | /// handle arbitrarily large ICMP echo ("ping") requests, where the all received bytes |
56 | /// need to be sent back, without heap allocation. |
57 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>; |
58 | |
59 | /// Construct a transmit token. |
60 | /// |
61 | /// If there is free space in the transmit buffer to transmit a packet, this function must return `Some`. |
62 | /// If there isn't, it must return `None`, and wake `cx.waker()` when space becomes available. |
63 | /// |
64 | /// Note that [`TxToken::consume`] is infallible, so it is not allowed to return a token |
65 | /// if there is no free space and fail later. |
66 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>>; |
67 | |
68 | /// Get the link state. |
69 | /// |
70 | /// This function must return the current link state of the device, and wake `cx.waker()` when |
71 | /// the link state changes. |
72 | fn link_state(&mut self, cx: &mut Context) -> LinkState; |
73 | |
74 | /// Get a description of device capabilities. |
75 | fn capabilities(&self) -> Capabilities; |
76 | |
77 | /// Get the device's hardware address. |
78 | /// |
79 | /// The returned hardware address also determines the "medium" of this driver. This indicates |
80 | /// what kind of packet the sent/received bytes are, and determines some behaviors of |
81 | /// the interface. For example, ARP/NDISC address resolution is only done for Ethernet mediums. |
82 | fn hardware_address(&self) -> HardwareAddress; |
83 | } |
84 | |
85 | impl<T: ?Sized + Driver> Driver for &mut T { |
86 | type RxToken<'a> = T::RxToken<'a> |
87 | where |
88 | Self: 'a; |
89 | type TxToken<'a> = T::TxToken<'a> |
90 | where |
91 | Self: 'a; |
92 | |
93 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { |
94 | T::transmit(self, cx) |
95 | } |
96 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { |
97 | T::receive(self, cx) |
98 | } |
99 | fn capabilities(&self) -> Capabilities { |
100 | T::capabilities(self) |
101 | } |
102 | fn link_state(&mut self, cx: &mut Context) -> LinkState { |
103 | T::link_state(self, cx) |
104 | } |
105 | fn hardware_address(&self) -> HardwareAddress { |
106 | T::hardware_address(self) |
107 | } |
108 | } |
109 | |
110 | /// A token to receive a single network packet. |
111 | pub trait RxToken { |
112 | /// Consumes the token to receive a single network packet. |
113 | /// |
114 | /// This method receives a packet and then calls the given closure `f` with the raw |
115 | /// packet bytes as argument. |
116 | fn consume<R, F>(self, f: F) -> R |
117 | where |
118 | F: FnOnce(&mut [u8]) -> R; |
119 | } |
120 | |
121 | /// A token to transmit a single network packet. |
122 | pub trait TxToken { |
123 | /// Consumes the token to send a single network packet. |
124 | /// |
125 | /// This method constructs a transmit buffer of size `len` and calls the passed |
126 | /// closure `f` with a mutable reference to that buffer. The closure should construct |
127 | /// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure |
128 | /// returns, the transmit buffer is sent out. |
129 | fn consume<R, F>(self, len: usize, f: F) -> R |
130 | where |
131 | F: FnOnce(&mut [u8]) -> R; |
132 | } |
133 | |
134 | /// A description of device capabilities. |
135 | /// |
136 | /// Higher-level protocols may achieve higher throughput or lower latency if they consider |
137 | /// the bandwidth or packet size limitations. |
138 | #[derive (Debug, Clone, Default)] |
139 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
140 | #[non_exhaustive ] |
141 | pub struct Capabilities { |
142 | /// Maximum transmission unit. |
143 | /// |
144 | /// The network device is unable to send or receive frames larger than the value returned |
145 | /// by this function. |
146 | /// |
147 | /// For Ethernet devices, this is the maximum Ethernet frame size, including the Ethernet header (14 octets), but |
148 | /// *not* including the Ethernet FCS (4 octets). Therefore, Ethernet MTU = IP MTU + 14. |
149 | /// |
150 | /// Note that in Linux and other OSes, "MTU" is the IP MTU, not the Ethernet MTU, even for Ethernet |
151 | /// devices. This is a common source of confusion. |
152 | /// |
153 | /// Most common IP MTU is 1500. Minimum is 576 (for IPv4) or 1280 (for IPv6). Maximum is 9216 octets. |
154 | pub max_transmission_unit: usize, |
155 | |
156 | /// Maximum burst size, in terms of MTU. |
157 | /// |
158 | /// The network device is unable to send or receive bursts large than the value returned |
159 | /// by this function. |
160 | /// |
161 | /// If `None`, there is no fixed limit on burst size, e.g. if network buffers are |
162 | /// dynamically allocated. |
163 | pub max_burst_size: Option<usize>, |
164 | |
165 | /// Checksum behavior. |
166 | /// |
167 | /// If the network device is capable of verifying or computing checksums for some protocols, |
168 | /// it can request that the stack not do so in software to improve performance. |
169 | pub checksum: ChecksumCapabilities, |
170 | } |
171 | |
172 | /// A description of checksum behavior for every supported protocol. |
173 | #[derive (Debug, Clone, Default)] |
174 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
175 | #[non_exhaustive ] |
176 | pub struct ChecksumCapabilities { |
177 | /// Checksum behavior for IPv4. |
178 | pub ipv4: Checksum, |
179 | /// Checksum behavior for UDP. |
180 | pub udp: Checksum, |
181 | /// Checksum behavior for TCP. |
182 | pub tcp: Checksum, |
183 | /// Checksum behavior for ICMPv4. |
184 | pub icmpv4: Checksum, |
185 | /// Checksum behavior for ICMPv6. |
186 | pub icmpv6: Checksum, |
187 | } |
188 | |
189 | /// A description of checksum behavior for a particular protocol. |
190 | #[derive (Debug, Clone, Copy)] |
191 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
192 | pub enum Checksum { |
193 | /// Verify checksum when receiving and compute checksum when sending. |
194 | Both, |
195 | /// Verify checksum when receiving. |
196 | Rx, |
197 | /// Compute checksum before sending. |
198 | Tx, |
199 | /// Ignore checksum completely. |
200 | None, |
201 | } |
202 | |
203 | impl Default for Checksum { |
204 | fn default() -> Checksum { |
205 | Checksum::Both |
206 | } |
207 | } |
208 | |
209 | /// The link state of a network device. |
210 | #[derive (PartialEq, Eq, Clone, Copy)] |
211 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
212 | pub enum LinkState { |
213 | /// The link is down. |
214 | Down, |
215 | /// The link is up. |
216 | Up, |
217 | } |
218 | |