1#![no_std]
2#![allow(async_fn_in_trait)]
3#![warn(missing_docs)]
4#![doc = include_str!("../README.md")]
5
6#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
8
9#[cfg(not(any(feature = "proto-ipv4", feature = "proto-ipv6")))]
10compile_error!("You must enable at least one of the following features: proto-ipv4, proto-ipv6");
11
12pub(crate) mod fmt;
14
15#[cfg(feature = "dns")]
16pub mod dns;
17mod driver_util;
18#[cfg(feature = "icmp")]
19pub mod icmp;
20#[cfg(feature = "raw")]
21pub mod raw;
22#[cfg(feature = "tcp")]
23pub mod tcp;
24mod time;
25#[cfg(feature = "udp")]
26pub mod udp;
27
28use core::cell::RefCell;
29use core::future::{poll_fn, Future};
30use core::mem::MaybeUninit;
31use core::pin::pin;
32use core::task::{Context, Poll};
33
34pub use embassy_net_driver as driver;
35use embassy_net_driver::{Driver, LinkState};
36use embassy_sync::waitqueue::WakerRegistration;
37use embassy_time::{Instant, Timer};
38use heapless::Vec;
39#[cfg(feature = "dns")]
40pub use smoltcp::config::DNS_MAX_SERVER_COUNT;
41#[cfg(feature = "multicast")]
42pub use smoltcp::iface::MulticastError;
43#[cfg(any(feature = "dns", feature = "dhcpv4"))]
44use smoltcp::iface::SocketHandle;
45use smoltcp::iface::{Interface, SocketSet, SocketStorage};
46use smoltcp::phy::Medium;
47#[cfg(feature = "dhcpv4")]
48use smoltcp::socket::dhcpv4::{self, RetryConfig};
49#[cfg(feature = "medium-ethernet")]
50pub use smoltcp::wire::EthernetAddress;
51#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154", feature = "medium-ip"))]
52pub use smoltcp::wire::HardwareAddress;
53#[cfg(any(feature = "udp", feature = "tcp"))]
54pub use smoltcp::wire::IpListenEndpoint;
55#[cfg(feature = "medium-ieee802154")]
56pub use smoltcp::wire::{Ieee802154Address, Ieee802154Frame};
57pub use smoltcp::wire::{IpAddress, IpCidr, IpEndpoint};
58#[cfg(feature = "proto-ipv4")]
59pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
60#[cfg(feature = "proto-ipv6")]
61pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
62
63use crate::driver_util::DriverAdapter;
64use crate::time::{instant_from_smoltcp, instant_to_smoltcp};
65
66const LOCAL_PORT_MIN: u16 = 1025;
67const LOCAL_PORT_MAX: u16 = 65535;
68#[cfg(feature = "dns")]
69const MAX_QUERIES: usize = 4;
70#[cfg(feature = "dhcpv4-hostname")]
71const MAX_HOSTNAME_LEN: usize = 32;
72
73pub struct StackResources<const SOCK: usize> {
75 sockets: MaybeUninit<[SocketStorage<'static>; SOCK]>,
76 inner: MaybeUninit<RefCell<Inner>>,
77 #[cfg(feature = "dns")]
78 queries: MaybeUninit<[Option<dns::DnsQuery>; MAX_QUERIES]>,
79 #[cfg(feature = "dhcpv4-hostname")]
80 hostname: HostnameResources,
81}
82
83#[cfg(feature = "dhcpv4-hostname")]
84struct HostnameResources {
85 option: MaybeUninit<smoltcp::wire::DhcpOption<'static>>,
86 data: MaybeUninit<[u8; MAX_HOSTNAME_LEN]>,
87}
88
89impl<const SOCK: usize> StackResources<SOCK> {
90 pub const fn new() -> Self {
92 Self {
93 sockets: MaybeUninit::uninit(),
94 inner: MaybeUninit::uninit(),
95 #[cfg(feature = "dns")]
96 queries: MaybeUninit::uninit(),
97 #[cfg(feature = "dhcpv4-hostname")]
98 hostname: HostnameResources {
99 option: MaybeUninit::uninit(),
100 data: MaybeUninit::uninit(),
101 },
102 }
103 }
104}
105
106#[cfg(feature = "proto-ipv4")]
108#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct StaticConfigV4 {
110 pub address: Ipv4Cidr,
112 pub gateway: Option<Ipv4Address>,
114 pub dns_servers: Vec<Ipv4Address, 3>,
116}
117
118#[cfg(feature = "proto-ipv6")]
120#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct StaticConfigV6 {
122 pub address: Ipv6Cidr,
124 pub gateway: Option<Ipv6Address>,
126 pub dns_servers: Vec<Ipv6Address, 3>,
128}
129
130#[cfg(feature = "dhcpv4")]
132#[derive(Debug, Clone, PartialEq, Eq)]
133#[non_exhaustive]
134pub struct DhcpConfig {
135 pub max_lease_duration: Option<embassy_time::Duration>,
140 pub retry_config: RetryConfig,
142 pub ignore_naks: bool,
146 pub server_port: u16,
148 pub client_port: u16,
150 #[cfg(feature = "dhcpv4-hostname")]
152 pub hostname: Option<heapless::String<MAX_HOSTNAME_LEN>>,
153}
154
155#[cfg(feature = "dhcpv4")]
156impl Default for DhcpConfig {
157 fn default() -> Self {
158 Self {
159 max_lease_duration: Default::default(),
160 retry_config: Default::default(),
161 ignore_naks: Default::default(),
162 server_port: smoltcp::wire::DHCP_SERVER_PORT,
163 client_port: smoltcp::wire::DHCP_CLIENT_PORT,
164 #[cfg(feature = "dhcpv4-hostname")]
165 hostname: None,
166 }
167 }
168}
169
170#[derive(Debug, Clone, Default)]
172#[non_exhaustive]
173pub struct Config {
174 #[cfg(feature = "proto-ipv4")]
176 pub ipv4: ConfigV4,
177 #[cfg(feature = "proto-ipv6")]
179 pub ipv6: ConfigV6,
180}
181
182impl Config {
183 #[cfg(feature = "proto-ipv4")]
185 pub const fn ipv4_static(config: StaticConfigV4) -> Self {
186 Self {
187 ipv4: ConfigV4::Static(config),
188 #[cfg(feature = "proto-ipv6")]
189 ipv6: ConfigV6::None,
190 }
191 }
192
193 #[cfg(feature = "proto-ipv6")]
195 pub const fn ipv6_static(config: StaticConfigV6) -> Self {
196 Self {
197 #[cfg(feature = "proto-ipv4")]
198 ipv4: ConfigV4::None,
199 ipv6: ConfigV6::Static(config),
200 }
201 }
202
203 #[cfg(feature = "dhcpv4")]
211 pub const fn dhcpv4(config: DhcpConfig) -> Self {
212 Self {
213 ipv4: ConfigV4::Dhcp(config),
214 #[cfg(feature = "proto-ipv6")]
215 ipv6: ConfigV6::None,
216 }
217 }
218}
219
220#[cfg(feature = "proto-ipv4")]
222#[derive(Debug, Clone, Default)]
223pub enum ConfigV4 {
224 #[default]
226 None,
227 Static(StaticConfigV4),
229 #[cfg(feature = "dhcpv4")]
231 Dhcp(DhcpConfig),
232}
233
234#[cfg(feature = "proto-ipv6")]
236#[derive(Debug, Clone, Default)]
237pub enum ConfigV6 {
238 #[default]
240 None,
241 Static(StaticConfigV6),
243}
244
245pub struct Runner<'d, D: Driver> {
249 driver: D,
250 stack: Stack<'d>,
251}
252
253#[derive(Copy, Clone)]
258pub struct Stack<'d> {
259 inner: &'d RefCell<Inner>,
260}
261
262pub(crate) struct Inner {
263 pub(crate) sockets: SocketSet<'static>, pub(crate) iface: Interface,
265 pub(crate) waker: WakerRegistration,
267 state_waker: WakerRegistration,
269 hardware_address: HardwareAddress,
270 next_local_port: u16,
271 link_up: bool,
272 #[cfg(feature = "proto-ipv4")]
273 static_v4: Option<StaticConfigV4>,
274 #[cfg(feature = "proto-ipv6")]
275 static_v6: Option<StaticConfigV6>,
276 #[cfg(feature = "dhcpv4")]
277 dhcp_socket: Option<SocketHandle>,
278 #[cfg(feature = "dns")]
279 dns_socket: SocketHandle,
280 #[cfg(feature = "dns")]
281 dns_waker: WakerRegistration,
282 #[cfg(feature = "dhcpv4-hostname")]
283 hostname: *mut HostnameResources,
284}
285
286fn _assert_covariant<'a, 'b: 'a>(x: Stack<'b>) -> Stack<'a> {
287 x
288}
289
290pub fn new<'d, D: Driver, const SOCK: usize>(
292 mut driver: D,
293 config: Config,
294 resources: &'d mut StackResources<SOCK>,
295 random_seed: u64,
296) -> (Stack<'d>, Runner<'d, D>) {
297 let (hardware_address, medium) = to_smoltcp_hardware_address(driver.hardware_address());
298 let mut iface_cfg = smoltcp::iface::Config::new(hardware_address);
299 iface_cfg.random_seed = random_seed;
300
301 let iface = Interface::new(
302 iface_cfg,
303 &mut DriverAdapter {
304 inner: &mut driver,
305 cx: None,
306 medium,
307 },
308 instant_to_smoltcp(Instant::now()),
309 );
310
311 unsafe fn transmute_slice<T>(x: &mut [T]) -> &'static mut [T] {
312 core::mem::transmute(x)
313 }
314
315 let sockets = resources.sockets.write([SocketStorage::EMPTY; SOCK]);
316 #[allow(unused_mut)]
317 let mut sockets: SocketSet<'static> = SocketSet::new(unsafe { transmute_slice(sockets) });
318
319 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN;
320
321 #[cfg(feature = "dns")]
322 let dns_socket = sockets.add(dns::Socket::new(
323 &[],
324 managed::ManagedSlice::Borrowed(unsafe {
325 transmute_slice(resources.queries.write([const { None }; MAX_QUERIES]))
326 }),
327 ));
328
329 let mut inner = Inner {
330 sockets,
331 iface,
332 waker: WakerRegistration::new(),
333 state_waker: WakerRegistration::new(),
334 next_local_port,
335 hardware_address,
336 link_up: false,
337 #[cfg(feature = "proto-ipv4")]
338 static_v4: None,
339 #[cfg(feature = "proto-ipv6")]
340 static_v6: None,
341 #[cfg(feature = "dhcpv4")]
342 dhcp_socket: None,
343 #[cfg(feature = "dns")]
344 dns_socket,
345 #[cfg(feature = "dns")]
346 dns_waker: WakerRegistration::new(),
347 #[cfg(feature = "dhcpv4-hostname")]
348 hostname: &mut resources.hostname,
349 };
350
351 #[cfg(feature = "proto-ipv4")]
352 inner.set_config_v4(config.ipv4);
353 #[cfg(feature = "proto-ipv6")]
354 inner.set_config_v6(config.ipv6);
355 inner.apply_static_config();
356
357 let inner = &*resources.inner.write(RefCell::new(inner));
358 let stack = Stack { inner };
359 (stack, Runner { driver, stack })
360}
361
362fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) {
363 match addr {
364 #[cfg(feature = "medium-ethernet")]
365 driver::HardwareAddress::Ethernet(eth) => (HardwareAddress::Ethernet(EthernetAddress(eth)), Medium::Ethernet),
366 #[cfg(feature = "medium-ieee802154")]
367 driver::HardwareAddress::Ieee802154(ieee) => (
368 HardwareAddress::Ieee802154(Ieee802154Address::Extended(ieee)),
369 Medium::Ieee802154,
370 ),
371 #[cfg(feature = "medium-ip")]
372 driver::HardwareAddress::Ip => (HardwareAddress::Ip, Medium::Ip),
373
374 #[allow(unreachable_patterns)]
375 _ => panic!(
376 "Unsupported medium {:?}. Make sure to enable the right medium feature in embassy-net's Cargo features.",
377 addr
378 ),
379 }
380}
381
382impl<'d> Stack<'d> {
383 fn with<R>(&self, f: impl FnOnce(&Inner) -> R) -> R {
384 f(&self.inner.borrow())
385 }
386
387 fn with_mut<R>(&self, f: impl FnOnce(&mut Inner) -> R) -> R {
388 f(&mut self.inner.borrow_mut())
389 }
390
391 pub fn hardware_address(&self) -> HardwareAddress {
393 self.with(|i| i.hardware_address)
394 }
395
396 pub fn is_link_up(&self) -> bool {
398 self.with(|i| i.link_up)
399 }
400
401 pub fn is_config_up(&self) -> bool {
404 let v4_up;
405 let v6_up;
406
407 #[cfg(feature = "proto-ipv4")]
408 {
409 v4_up = self.config_v4().is_some();
410 }
411 #[cfg(not(feature = "proto-ipv4"))]
412 {
413 v4_up = false;
414 }
415
416 #[cfg(feature = "proto-ipv6")]
417 {
418 v6_up = self.config_v6().is_some();
419 }
420 #[cfg(not(feature = "proto-ipv6"))]
421 {
422 v6_up = false;
423 }
424
425 v4_up || v6_up
426 }
427
428 pub async fn wait_link_up(&self) {
430 self.wait(|| self.is_link_up()).await
431 }
432
433 pub async fn wait_link_down(&self) {
435 self.wait(|| !self.is_link_up()).await
436 }
437
438 pub async fn wait_config_up(&self) {
468 self.wait(|| self.is_config_up()).await
469 }
470
471 pub async fn wait_config_down(&self) {
473 self.wait(|| !self.is_config_up()).await
474 }
475
476 fn wait<'a>(&'a self, mut predicate: impl FnMut() -> bool + 'a) -> impl Future<Output = ()> + 'a {
477 poll_fn(move |cx| {
478 if predicate() {
479 Poll::Ready(())
480 } else {
481 trace!("Waiting for config up");
484
485 self.with_mut(|i| {
486 i.state_waker.register(cx.waker());
487 });
488
489 Poll::Pending
490 }
491 })
492 }
493
494 #[cfg(feature = "proto-ipv4")]
499 pub fn config_v4(&self) -> Option<StaticConfigV4> {
500 self.with(|i| i.static_v4.clone())
501 }
502
503 #[cfg(feature = "proto-ipv6")]
505 pub fn config_v6(&self) -> Option<StaticConfigV6> {
506 self.with(|i| i.static_v6.clone())
507 }
508
509 #[cfg(feature = "proto-ipv4")]
511 pub fn set_config_v4(&self, config: ConfigV4) {
512 self.with_mut(|i| {
513 i.set_config_v4(config);
514 i.apply_static_config();
515 })
516 }
517
518 #[cfg(feature = "proto-ipv6")]
520 pub fn set_config_v6(&self, config: ConfigV6) {
521 self.with_mut(|i| {
522 i.set_config_v6(config);
523 i.apply_static_config();
524 })
525 }
526
527 #[cfg(feature = "dns")]
529 pub async fn dns_query(
530 &self,
531 name: &str,
532 qtype: dns::DnsQueryType,
533 ) -> Result<Vec<IpAddress, { smoltcp::config::DNS_MAX_RESULT_COUNT }>, dns::Error> {
534 match qtype {
536 #[cfg(feature = "proto-ipv4")]
537 dns::DnsQueryType::A => {
538 if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
539 return Ok([ip].into_iter().collect());
540 }
541 }
542 #[cfg(feature = "proto-ipv6")]
543 dns::DnsQueryType::Aaaa => {
544 if let Ok(ip) = name.parse().map(IpAddress::Ipv6) {
545 return Ok([ip].into_iter().collect());
546 }
547 }
548 _ => {}
549 }
550
551 let query = poll_fn(|cx| {
552 self.with_mut(|i| {
553 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
554 match socket.start_query(i.iface.context(), name, qtype) {
555 Ok(handle) => {
556 i.waker.wake();
557 Poll::Ready(Ok(handle))
558 }
559 Err(dns::StartQueryError::NoFreeSlot) => {
560 i.dns_waker.register(cx.waker());
561 Poll::Pending
562 }
563 Err(e) => Poll::Ready(Err(e)),
564 }
565 })
566 })
567 .await?;
568
569 #[must_use = "to delay the drop handler invocation to the end of the scope"]
570 struct OnDrop<F: FnOnce()> {
571 f: core::mem::MaybeUninit<F>,
572 }
573
574 impl<F: FnOnce()> OnDrop<F> {
575 fn new(f: F) -> Self {
576 Self {
577 f: core::mem::MaybeUninit::new(f),
578 }
579 }
580
581 fn defuse(self) {
582 core::mem::forget(self)
583 }
584 }
585
586 impl<F: FnOnce()> Drop for OnDrop<F> {
587 fn drop(&mut self) {
588 unsafe { self.f.as_ptr().read()() }
589 }
590 }
591
592 let drop = OnDrop::new(|| {
593 self.with_mut(|i| {
594 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
595 socket.cancel_query(query);
596 i.waker.wake();
597 i.dns_waker.wake();
598 })
599 });
600
601 let res = poll_fn(|cx| {
602 self.with_mut(|i| {
603 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
604 match socket.get_query_result(query) {
605 Ok(addrs) => {
606 i.dns_waker.wake();
607 Poll::Ready(Ok(addrs))
608 }
609 Err(dns::GetQueryResultError::Pending) => {
610 socket.register_query_waker(query, cx.waker());
611 Poll::Pending
612 }
613 Err(e) => {
614 i.dns_waker.wake();
615 Poll::Ready(Err(e.into()))
616 }
617 }
618 })
619 })
620 .await;
621
622 drop.defuse();
623
624 res
625 }
626}
627
628#[cfg(feature = "multicast")]
629impl<'d> Stack<'d> {
630 pub fn join_multicast_group(&self, addr: impl Into<IpAddress>) -> Result<(), MulticastError> {
632 self.with_mut(|i| i.iface.join_multicast_group(addr))
633 }
634
635 pub fn leave_multicast_group(&self, addr: impl Into<IpAddress>) -> Result<(), MulticastError> {
637 self.with_mut(|i| i.iface.leave_multicast_group(addr))
638 }
639
640 pub fn has_multicast_group(&self, addr: impl Into<IpAddress>) -> bool {
642 self.with(|i| i.iface.has_multicast_group(addr))
643 }
644}
645
646impl Inner {
647 #[allow(clippy::absurd_extreme_comparisons)]
648 pub fn get_local_port(&mut self) -> u16 {
649 let res = self.next_local_port;
650 self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 };
651 res
652 }
653
654 #[cfg(feature = "proto-ipv4")]
655 pub fn set_config_v4(&mut self, config: ConfigV4) {
656 self.static_v4 = match config.clone() {
658 ConfigV4::None => None,
659 #[cfg(feature = "dhcpv4")]
660 ConfigV4::Dhcp(_) => None,
661 ConfigV4::Static(c) => Some(c),
662 };
663
664 #[cfg(feature = "dhcpv4")]
666 match config {
667 ConfigV4::Dhcp(c) => {
668 if self.dhcp_socket.is_none() {
670 let socket = smoltcp::socket::dhcpv4::Socket::new();
671 let handle = self.sockets.add(socket);
672 self.dhcp_socket = Some(handle);
673 }
674
675 let socket = self.sockets.get_mut::<dhcpv4::Socket>(unwrap!(self.dhcp_socket));
677 socket.set_ignore_naks(c.ignore_naks);
678 socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp));
679 socket.set_ports(c.server_port, c.client_port);
680 socket.set_retry_config(c.retry_config);
681
682 socket.set_outgoing_options(&[]);
683 #[cfg(feature = "dhcpv4-hostname")]
684 if let Some(h) = c.hostname {
685 let hostname = unsafe { &mut *self.hostname };
690
691 let data = hostname.data.write([0; MAX_HOSTNAME_LEN]);
693 data[..h.len()].copy_from_slice(h.as_bytes());
694 let data: &[u8] = &data[..h.len()];
695
696 let option = hostname.option.write(smoltcp::wire::DhcpOption { data, kind: 12 });
698 socket.set_outgoing_options(core::slice::from_ref(option));
699 }
700
701 socket.reset();
702 }
703 _ => {
704 if let Some(socket) = self.dhcp_socket {
706 self.sockets.remove(socket);
707 self.dhcp_socket = None;
708 }
709 }
710 }
711 }
712
713 #[cfg(feature = "proto-ipv6")]
714 pub fn set_config_v6(&mut self, config: ConfigV6) {
715 self.static_v6 = match config {
716 ConfigV6::None => None,
717 ConfigV6::Static(c) => Some(c),
718 };
719 }
720
721 fn apply_static_config(&mut self) {
722 let mut addrs = Vec::new();
723 #[cfg(feature = "dns")]
724 let mut dns_servers: Vec<_, 6> = Vec::new();
725 #[cfg(feature = "proto-ipv4")]
726 let mut gateway_v4 = None;
727 #[cfg(feature = "proto-ipv6")]
728 let mut gateway_v6 = None;
729
730 #[cfg(feature = "proto-ipv4")]
731 if let Some(config) = &self.static_v4 {
732 debug!("IPv4: UP");
733 debug!(" IP address: {:?}", config.address);
734 debug!(" Default gateway: {:?}", config.gateway);
735
736 unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok());
737 gateway_v4 = config.gateway;
738 #[cfg(feature = "dns")]
739 for s in &config.dns_servers {
740 debug!(" DNS server: {:?}", s);
741 unwrap!(dns_servers.push(s.clone().into()).ok());
742 }
743 } else {
744 info!("IPv4: DOWN");
745 }
746
747 #[cfg(feature = "proto-ipv6")]
748 if let Some(config) = &self.static_v6 {
749 debug!("IPv6: UP");
750 debug!(" IP address: {:?}", config.address);
751 debug!(" Default gateway: {:?}", config.gateway);
752
753 unwrap!(addrs.push(IpCidr::Ipv6(config.address)).ok());
754 gateway_v6 = config.gateway.into();
755 #[cfg(feature = "dns")]
756 for s in &config.dns_servers {
757 debug!(" DNS server: {:?}", s);
758 unwrap!(dns_servers.push(s.clone().into()).ok());
759 }
760 } else {
761 info!("IPv6: DOWN");
762 }
763
764 self.iface.update_ip_addrs(|a| *a = addrs);
766
767 #[cfg(feature = "proto-ipv4")]
769 if let Some(gateway) = gateway_v4 {
770 unwrap!(self.iface.routes_mut().add_default_ipv4_route(gateway));
771 } else {
772 self.iface.routes_mut().remove_default_ipv4_route();
773 }
774 #[cfg(feature = "proto-ipv6")]
775 if let Some(gateway) = gateway_v6 {
776 unwrap!(self.iface.routes_mut().add_default_ipv6_route(gateway));
777 } else {
778 self.iface.routes_mut().remove_default_ipv6_route();
779 }
780
781 #[cfg(feature = "dns")]
783 if !dns_servers.is_empty() {
784 let count = if dns_servers.len() > DNS_MAX_SERVER_COUNT {
785 warn!("Number of DNS servers exceeds DNS_MAX_SERVER_COUNT, truncating list.");
786 DNS_MAX_SERVER_COUNT
787 } else {
788 dns_servers.len()
789 };
790 self.sockets
791 .get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
792 .update_servers(&dns_servers[..count]);
793 }
794
795 self.state_waker.wake();
796 }
797
798 fn poll<D: Driver>(&mut self, cx: &mut Context<'_>, driver: &mut D) {
799 self.waker.register(cx.waker());
800
801 let (_hardware_addr, medium) = to_smoltcp_hardware_address(driver.hardware_address());
802
803 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
804 {
805 let do_set = match medium {
806 #[cfg(feature = "medium-ethernet")]
807 Medium::Ethernet => true,
808 #[cfg(feature = "medium-ieee802154")]
809 Medium::Ieee802154 => true,
810 #[allow(unreachable_patterns)]
811 _ => false,
812 };
813 if do_set {
814 self.iface.set_hardware_addr(_hardware_addr);
815 }
816 }
817
818 let timestamp = instant_to_smoltcp(Instant::now());
819 let mut smoldev = DriverAdapter {
820 cx: Some(cx),
821 inner: driver,
822 medium,
823 };
824 self.iface.poll(timestamp, &mut smoldev, &mut self.sockets);
825
826 let old_link_up = self.link_up;
828 self.link_up = driver.link_state(cx) == LinkState::Up;
829
830 if old_link_up != self.link_up {
832 info!("link_up = {:?}", self.link_up);
833 self.state_waker.wake();
834 }
835
836 #[cfg(feature = "dhcpv4")]
837 if let Some(dhcp_handle) = self.dhcp_socket {
838 let socket = self.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
839
840 let configure = if self.link_up {
841 if old_link_up != self.link_up {
842 socket.reset();
843 }
844 match socket.poll() {
845 None => false,
846 Some(dhcpv4::Event::Deconfigured) => {
847 self.static_v4 = None;
848 true
849 }
850 Some(dhcpv4::Event::Configured(config)) => {
851 self.static_v4 = Some(StaticConfigV4 {
852 address: config.address,
853 gateway: config.router,
854 dns_servers: config.dns_servers,
855 });
856 true
857 }
858 }
859 } else if old_link_up {
860 socket.reset();
861 self.static_v4 = None;
862 true
863 } else {
864 false
865 };
866 if configure {
867 self.apply_static_config()
868 }
869 }
870
871 if let Some(poll_at) = self.iface.poll_at(timestamp, &mut self.sockets) {
872 let t = pin!(Timer::at(instant_from_smoltcp(poll_at)));
873 if t.poll(cx).is_ready() {
874 cx.waker().wake_by_ref();
875 }
876 }
877 }
878}
879
880impl<'d, D: Driver> Runner<'d, D> {
881 pub async fn run(&mut self) -> ! {
885 poll_fn(|cx| {
886 self.stack.with_mut(|i| i.poll(cx, &mut self.driver));
887 Poll::<()>::Pending
888 })
889 .await;
890 unreachable!()
891 }
892}