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