aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-net/src/lib.rs307
-rw-r--r--embassy-net/src/stack.rs306
-rw-r--r--embassy-net/src/tcp.rs3
-rw-r--r--embassy-net/src/udp.rs3
4 files changed, 304 insertions, 315 deletions
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index e18e819cb..afe0d6da0 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -9,16 +9,28 @@
9pub(crate) mod fmt; 9pub(crate) mod fmt;
10 10
11pub mod device; 11pub mod device;
12mod stack;
13
14pub use stack::{Config, ConfigStrategy, Stack, StackResources};
15
16#[cfg(feature = "tcp")] 12#[cfg(feature = "tcp")]
17pub mod tcp; 13pub mod tcp;
18
19#[cfg(feature = "udp")] 14#[cfg(feature = "udp")]
20pub mod udp; 15pub mod udp;
21 16
17use core::cell::RefCell;
18use core::future::{poll_fn, Future};
19use core::task::{Context, Poll};
20
21use embassy_sync::waitqueue::WakerRegistration;
22use embassy_time::{Instant, Timer};
23use futures::pin_mut;
24use heapless::Vec;
25#[cfg(feature = "dhcpv4")]
26use smoltcp::iface::SocketHandle;
27use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage};
28#[cfg(feature = "medium-ethernet")]
29use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes};
30#[cfg(feature = "medium-ethernet")]
31use smoltcp::phy::Medium;
32#[cfg(feature = "dhcpv4")]
33use smoltcp::socket::dhcpv4;
22// smoltcp reexports 34// smoltcp reexports
23pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant}; 35pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant};
24#[cfg(feature = "medium-ethernet")] 36#[cfg(feature = "medium-ethernet")]
@@ -28,3 +40,288 @@ pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr};
28pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; 40pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
29#[cfg(feature = "udp")] 41#[cfg(feature = "udp")]
30pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint}; 42pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint};
43
44use crate::device::{Device, DeviceAdapter, LinkState};
45
46const LOCAL_PORT_MIN: u16 = 1025;
47const LOCAL_PORT_MAX: u16 = 65535;
48
49pub struct StackResources<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> {
50 addresses: [IpCidr; ADDR],
51 sockets: [SocketStorage<'static>; SOCK],
52
53 #[cfg(feature = "medium-ethernet")]
54 routes: [Option<(IpCidr, Route)>; 1],
55 #[cfg(feature = "medium-ethernet")]
56 neighbor_cache: [Option<(IpAddress, Neighbor)>; NEIGHBOR],
57}
58
59impl<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> StackResources<ADDR, SOCK, NEIGHBOR> {
60 pub fn new() -> Self {
61 Self {
62 addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32); ADDR],
63 sockets: [SocketStorage::EMPTY; SOCK],
64 #[cfg(feature = "medium-ethernet")]
65 routes: [None; 1],
66 #[cfg(feature = "medium-ethernet")]
67 neighbor_cache: [None; NEIGHBOR],
68 }
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct Config {
74 pub address: Ipv4Cidr,
75 pub gateway: Option<Ipv4Address>,
76 pub dns_servers: Vec<Ipv4Address, 3>,
77}
78
79pub enum ConfigStrategy {
80 Static(Config),
81 #[cfg(feature = "dhcpv4")]
82 Dhcp,
83}
84
85pub struct Stack<D: Device> {
86 pub(crate) socket: RefCell<SocketStack>,
87 inner: RefCell<Inner<D>>,
88}
89
90struct Inner<D: Device> {
91 device: D,
92 link_up: bool,
93 config: Option<Config>,
94 #[cfg(feature = "dhcpv4")]
95 dhcp_socket: Option<SocketHandle>,
96}
97
98pub(crate) struct SocketStack {
99 pub(crate) sockets: SocketSet<'static>,
100 pub(crate) iface: Interface<'static>,
101 pub(crate) waker: WakerRegistration,
102 next_local_port: u16,
103}
104
105impl<D: Device + 'static> Stack<D> {
106 pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>(
107 mut device: D,
108 config: ConfigStrategy,
109 resources: &'static mut StackResources<ADDR, SOCK, NEIGH>,
110 random_seed: u64,
111 ) -> Self {
112 #[cfg(feature = "medium-ethernet")]
113 let medium = device.capabilities().medium;
114
115 #[cfg(feature = "medium-ethernet")]
116 let ethernet_addr = if medium == Medium::Ethernet {
117 device.ethernet_address()
118 } else {
119 [0, 0, 0, 0, 0, 0]
120 };
121
122 let mut b = InterfaceBuilder::new();
123 b = b.ip_addrs(&mut resources.addresses[..]);
124 b = b.random_seed(random_seed);
125
126 #[cfg(feature = "medium-ethernet")]
127 if medium == Medium::Ethernet {
128 b = b.hardware_addr(HardwareAddress::Ethernet(EthernetAddress(ethernet_addr)));
129 b = b.neighbor_cache(NeighborCache::new(&mut resources.neighbor_cache[..]));
130 b = b.routes(Routes::new(&mut resources.routes[..]));
131 }
132
133 let iface = b.finalize(&mut DeviceAdapter {
134 inner: &mut device,
135 cx: None,
136 });
137
138 let sockets = SocketSet::new(&mut resources.sockets[..]);
139
140 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN;
141
142 let mut inner = Inner {
143 device,
144 link_up: false,
145 config: None,
146 #[cfg(feature = "dhcpv4")]
147 dhcp_socket: None,
148 };
149 let mut socket = SocketStack {
150 sockets,
151 iface,
152 waker: WakerRegistration::new(),
153 next_local_port,
154 };
155
156 match config {
157 ConfigStrategy::Static(config) => inner.apply_config(&mut socket, config),
158 #[cfg(feature = "dhcpv4")]
159 ConfigStrategy::Dhcp => {
160 let handle = socket.sockets.add(smoltcp::socket::dhcpv4::Socket::new());
161 inner.dhcp_socket = Some(handle);
162 }
163 }
164
165 Self {
166 socket: RefCell::new(socket),
167 inner: RefCell::new(inner),
168 }
169 }
170
171 fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R {
172 f(&*self.socket.borrow(), &*self.inner.borrow())
173 }
174
175 fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R {
176 f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut())
177 }
178
179 pub fn ethernet_address(&self) -> [u8; 6] {
180 self.with(|_s, i| i.device.ethernet_address())
181 }
182
183 pub fn is_link_up(&self) -> bool {
184 self.with(|_s, i| i.link_up)
185 }
186
187 pub fn is_config_up(&self) -> bool {
188 self.with(|_s, i| i.config.is_some())
189 }
190
191 pub fn config(&self) -> Option<Config> {
192 self.with(|_s, i| i.config.clone())
193 }
194
195 pub async fn run(&self) -> ! {
196 poll_fn(|cx| {
197 self.with_mut(|s, i| i.poll(cx, s));
198 Poll::<()>::Pending
199 })
200 .await;
201 unreachable!()
202 }
203}
204
205impl SocketStack {
206 #[allow(clippy::absurd_extreme_comparisons)]
207 pub fn get_local_port(&mut self) -> u16 {
208 let res = self.next_local_port;
209 self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 };
210 res
211 }
212}
213
214impl<D: Device + 'static> Inner<D> {
215 fn apply_config(&mut self, s: &mut SocketStack, config: Config) {
216 #[cfg(feature = "medium-ethernet")]
217 let medium = self.device.capabilities().medium;
218
219 debug!("Acquired IP configuration:");
220
221 debug!(" IP address: {}", config.address);
222 self.set_ipv4_addr(s, config.address);
223
224 #[cfg(feature = "medium-ethernet")]
225 if medium == Medium::Ethernet {
226 if let Some(gateway) = config.gateway {
227 debug!(" Default gateway: {}", gateway);
228 s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap();
229 } else {
230 debug!(" Default gateway: None");
231 s.iface.routes_mut().remove_default_ipv4_route();
232 }
233 }
234 for (i, s) in config.dns_servers.iter().enumerate() {
235 debug!(" DNS server {}: {}", i, s);
236 }
237
238 self.config = Some(config)
239 }
240
241 #[allow(unused)] // used only with dhcp
242 fn unapply_config(&mut self, s: &mut SocketStack) {
243 #[cfg(feature = "medium-ethernet")]
244 let medium = self.device.capabilities().medium;
245
246 debug!("Lost IP configuration");
247 self.set_ipv4_addr(s, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0));
248 #[cfg(feature = "medium-ethernet")]
249 if medium == Medium::Ethernet {
250 s.iface.routes_mut().remove_default_ipv4_route();
251 }
252 self.config = None
253 }
254
255 fn set_ipv4_addr(&mut self, s: &mut SocketStack, cidr: Ipv4Cidr) {
256 s.iface.update_ip_addrs(|addrs| {
257 let dest = addrs.iter_mut().next().unwrap();
258 *dest = IpCidr::Ipv4(cidr);
259 });
260 }
261
262 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
263 s.waker.register(cx.waker());
264
265 let timestamp = instant_to_smoltcp(Instant::now());
266 let mut smoldev = DeviceAdapter {
267 cx: Some(cx),
268 inner: &mut self.device,
269 };
270 if s.iface.poll(timestamp, &mut smoldev, &mut s.sockets).is_err() {
271 // If poll() returns error, it may not be done yet, so poll again later.
272 cx.waker().wake_by_ref();
273 return;
274 }
275
276 // Update link up
277 let old_link_up = self.link_up;
278 self.link_up = self.device.link_state(cx) == LinkState::Up;
279
280 // Print when changed
281 if old_link_up != self.link_up {
282 info!("link_up = {:?}", self.link_up);
283 }
284
285 #[cfg(feature = "dhcpv4")]
286 if let Some(dhcp_handle) = self.dhcp_socket {
287 let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
288
289 if self.link_up {
290 match socket.poll() {
291 None => {}
292 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
293 Some(dhcpv4::Event::Configured(config)) => {
294 let config = Config {
295 address: config.address,
296 gateway: config.router,
297 dns_servers: config.dns_servers,
298 };
299 self.apply_config(s, config)
300 }
301 }
302 } else if old_link_up {
303 socket.reset();
304 self.unapply_config(s);
305 }
306 }
307 //if old_link_up || self.link_up {
308 // self.poll_configurator(timestamp)
309 //}
310
311 if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) {
312 let t = Timer::at(instant_from_smoltcp(poll_at));
313 pin_mut!(t);
314 if t.poll(cx).is_ready() {
315 cx.waker().wake_by_ref();
316 }
317 }
318 }
319}
320
321fn instant_to_smoltcp(instant: Instant) -> SmolInstant {
322 SmolInstant::from_millis(instant.as_millis() as i64)
323}
324
325fn instant_from_smoltcp(instant: SmolInstant) -> Instant {
326 Instant::from_millis(instant.total_millis() as u64)
327}
diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs
deleted file mode 100644
index 21316e485..000000000
--- a/embassy-net/src/stack.rs
+++ /dev/null
@@ -1,306 +0,0 @@
1use core::cell::RefCell;
2use core::future::{poll_fn, Future};
3use core::task::{Context, Poll};
4
5use embassy_sync::waitqueue::WakerRegistration;
6use embassy_time::{Instant, Timer};
7use futures::pin_mut;
8use heapless::Vec;
9#[cfg(feature = "dhcpv4")]
10use smoltcp::iface::SocketHandle;
11use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage};
12#[cfg(feature = "medium-ethernet")]
13use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes};
14#[cfg(feature = "medium-ethernet")]
15use smoltcp::phy::Medium;
16#[cfg(feature = "dhcpv4")]
17use smoltcp::socket::dhcpv4;
18use smoltcp::time::Instant as SmolInstant;
19#[cfg(feature = "medium-ethernet")]
20use smoltcp::wire::{EthernetAddress, HardwareAddress, IpAddress};
21use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr};
22
23use crate::device::{Device, DeviceAdapter, LinkState};
24
25const LOCAL_PORT_MIN: u16 = 1025;
26const LOCAL_PORT_MAX: u16 = 65535;
27
28pub struct StackResources<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> {
29 addresses: [IpCidr; ADDR],
30 sockets: [SocketStorage<'static>; SOCK],
31
32 #[cfg(feature = "medium-ethernet")]
33 routes: [Option<(IpCidr, Route)>; 1],
34 #[cfg(feature = "medium-ethernet")]
35 neighbor_cache: [Option<(IpAddress, Neighbor)>; NEIGHBOR],
36}
37
38impl<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> StackResources<ADDR, SOCK, NEIGHBOR> {
39 pub fn new() -> Self {
40 Self {
41 addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32); ADDR],
42 sockets: [SocketStorage::EMPTY; SOCK],
43 #[cfg(feature = "medium-ethernet")]
44 routes: [None; 1],
45 #[cfg(feature = "medium-ethernet")]
46 neighbor_cache: [None; NEIGHBOR],
47 }
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct Config {
53 pub address: Ipv4Cidr,
54 pub gateway: Option<Ipv4Address>,
55 pub dns_servers: Vec<Ipv4Address, 3>,
56}
57
58pub enum ConfigStrategy {
59 Static(Config),
60 #[cfg(feature = "dhcpv4")]
61 Dhcp,
62}
63
64pub struct Stack<D: Device> {
65 pub(crate) socket: RefCell<SocketStack>,
66 inner: RefCell<Inner<D>>,
67}
68
69struct Inner<D: Device> {
70 device: D,
71 link_up: bool,
72 config: Option<Config>,
73 #[cfg(feature = "dhcpv4")]
74 dhcp_socket: Option<SocketHandle>,
75}
76
77pub(crate) struct SocketStack {
78 pub(crate) sockets: SocketSet<'static>,
79 pub(crate) iface: Interface<'static>,
80 pub(crate) waker: WakerRegistration,
81 next_local_port: u16,
82}
83
84impl<D: Device + 'static> Stack<D> {
85 pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>(
86 mut device: D,
87 config: ConfigStrategy,
88 resources: &'static mut StackResources<ADDR, SOCK, NEIGH>,
89 random_seed: u64,
90 ) -> Self {
91 #[cfg(feature = "medium-ethernet")]
92 let medium = device.capabilities().medium;
93
94 #[cfg(feature = "medium-ethernet")]
95 let ethernet_addr = if medium == Medium::Ethernet {
96 device.ethernet_address()
97 } else {
98 [0, 0, 0, 0, 0, 0]
99 };
100
101 let mut b = InterfaceBuilder::new();
102 b = b.ip_addrs(&mut resources.addresses[..]);
103 b = b.random_seed(random_seed);
104
105 #[cfg(feature = "medium-ethernet")]
106 if medium == Medium::Ethernet {
107 b = b.hardware_addr(HardwareAddress::Ethernet(EthernetAddress(ethernet_addr)));
108 b = b.neighbor_cache(NeighborCache::new(&mut resources.neighbor_cache[..]));
109 b = b.routes(Routes::new(&mut resources.routes[..]));
110 }
111
112 let iface = b.finalize(&mut DeviceAdapter {
113 inner: &mut device,
114 cx: None,
115 });
116
117 let sockets = SocketSet::new(&mut resources.sockets[..]);
118
119 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN;
120
121 let mut inner = Inner {
122 device,
123 link_up: false,
124 config: None,
125 #[cfg(feature = "dhcpv4")]
126 dhcp_socket: None,
127 };
128 let mut socket = SocketStack {
129 sockets,
130 iface,
131 waker: WakerRegistration::new(),
132 next_local_port,
133 };
134
135 match config {
136 ConfigStrategy::Static(config) => inner.apply_config(&mut socket, config),
137 #[cfg(feature = "dhcpv4")]
138 ConfigStrategy::Dhcp => {
139 let handle = socket.sockets.add(smoltcp::socket::dhcpv4::Socket::new());
140 inner.dhcp_socket = Some(handle);
141 }
142 }
143
144 Self {
145 socket: RefCell::new(socket),
146 inner: RefCell::new(inner),
147 }
148 }
149
150 fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R {
151 f(&*self.socket.borrow(), &*self.inner.borrow())
152 }
153
154 fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R {
155 f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut())
156 }
157
158 pub fn ethernet_address(&self) -> [u8; 6] {
159 self.with(|_s, i| i.device.ethernet_address())
160 }
161
162 pub fn is_link_up(&self) -> bool {
163 self.with(|_s, i| i.link_up)
164 }
165
166 pub fn is_config_up(&self) -> bool {
167 self.with(|_s, i| i.config.is_some())
168 }
169
170 pub fn config(&self) -> Option<Config> {
171 self.with(|_s, i| i.config.clone())
172 }
173
174 pub async fn run(&self) -> ! {
175 poll_fn(|cx| {
176 self.with_mut(|s, i| i.poll(cx, s));
177 Poll::<()>::Pending
178 })
179 .await;
180 unreachable!()
181 }
182}
183
184impl SocketStack {
185 #[allow(clippy::absurd_extreme_comparisons)]
186 pub fn get_local_port(&mut self) -> u16 {
187 let res = self.next_local_port;
188 self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 };
189 res
190 }
191}
192
193impl<D: Device + 'static> Inner<D> {
194 fn apply_config(&mut self, s: &mut SocketStack, config: Config) {
195 #[cfg(feature = "medium-ethernet")]
196 let medium = self.device.capabilities().medium;
197
198 debug!("Acquired IP configuration:");
199
200 debug!(" IP address: {}", config.address);
201 self.set_ipv4_addr(s, config.address);
202
203 #[cfg(feature = "medium-ethernet")]
204 if medium == Medium::Ethernet {
205 if let Some(gateway) = config.gateway {
206 debug!(" Default gateway: {}", gateway);
207 s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap();
208 } else {
209 debug!(" Default gateway: None");
210 s.iface.routes_mut().remove_default_ipv4_route();
211 }
212 }
213 for (i, s) in config.dns_servers.iter().enumerate() {
214 debug!(" DNS server {}: {}", i, s);
215 }
216
217 self.config = Some(config)
218 }
219
220 #[allow(unused)] // used only with dhcp
221 fn unapply_config(&mut self, s: &mut SocketStack) {
222 #[cfg(feature = "medium-ethernet")]
223 let medium = self.device.capabilities().medium;
224
225 debug!("Lost IP configuration");
226 self.set_ipv4_addr(s, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0));
227 #[cfg(feature = "medium-ethernet")]
228 if medium == Medium::Ethernet {
229 s.iface.routes_mut().remove_default_ipv4_route();
230 }
231 self.config = None
232 }
233
234 fn set_ipv4_addr(&mut self, s: &mut SocketStack, cidr: Ipv4Cidr) {
235 s.iface.update_ip_addrs(|addrs| {
236 let dest = addrs.iter_mut().next().unwrap();
237 *dest = IpCidr::Ipv4(cidr);
238 });
239 }
240
241 fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
242 s.waker.register(cx.waker());
243
244 let timestamp = instant_to_smoltcp(Instant::now());
245 let mut smoldev = DeviceAdapter {
246 cx: Some(cx),
247 inner: &mut self.device,
248 };
249 if s.iface.poll(timestamp, &mut smoldev, &mut s.sockets).is_err() {
250 // If poll() returns error, it may not be done yet, so poll again later.
251 cx.waker().wake_by_ref();
252 return;
253 }
254
255 // Update link up
256 let old_link_up = self.link_up;
257 self.link_up = self.device.link_state(cx) == LinkState::Up;
258
259 // Print when changed
260 if old_link_up != self.link_up {
261 info!("link_up = {:?}", self.link_up);
262 }
263
264 #[cfg(feature = "dhcpv4")]
265 if let Some(dhcp_handle) = self.dhcp_socket {
266 let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
267
268 if self.link_up {
269 match socket.poll() {
270 None => {}
271 Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
272 Some(dhcpv4::Event::Configured(config)) => {
273 let config = Config {
274 address: config.address,
275 gateway: config.router,
276 dns_servers: config.dns_servers,
277 };
278 self.apply_config(s, config)
279 }
280 }
281 } else if old_link_up {
282 socket.reset();
283 self.unapply_config(s);
284 }
285 }
286 //if old_link_up || self.link_up {
287 // self.poll_configurator(timestamp)
288 //}
289
290 if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) {
291 let t = Timer::at(instant_from_smoltcp(poll_at));
292 pin_mut!(t);
293 if t.poll(cx).is_ready() {
294 cx.waker().wake_by_ref();
295 }
296 }
297 }
298}
299
300fn instant_to_smoltcp(instant: Instant) -> SmolInstant {
301 SmolInstant::from_millis(instant.as_millis() as i64)
302}
303
304fn instant_from_smoltcp(instant: SmolInstant) -> Instant {
305 Instant::from_millis(instant.total_millis() as u64)
306}
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 0ed4b81e2..0dc8da73a 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -8,9 +8,8 @@ use smoltcp::socket::tcp;
8use smoltcp::time::Duration; 8use smoltcp::time::Duration;
9use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; 9use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
10 10
11use super::stack::Stack;
12use crate::device::Device; 11use crate::device::Device;
13use crate::stack::SocketStack; 12use crate::{SocketStack, Stack};
14 13
15#[derive(PartialEq, Eq, Clone, Copy, Debug)] 14#[derive(PartialEq, Eq, Clone, Copy, Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))] 15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 4ddad77d4..2f5334df3 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -7,8 +7,7 @@ use smoltcp::iface::{Interface, SocketHandle};
7use smoltcp::socket::udp::{self, PacketMetadata}; 7use smoltcp::socket::udp::{self, PacketMetadata};
8use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; 8use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
9 9
10use super::stack::SocketStack; 10use crate::{Device, SocketStack, Stack};
11use crate::{Device, Stack};
12 11
13#[derive(PartialEq, Eq, Clone, Copy, Debug)] 12#[derive(PartialEq, Eq, Clone, Copy, Debug)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))] 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]