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)]
109#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110pub struct StaticConfigV4 {
111 pub address: Ipv4Cidr,
113 pub gateway: Option<Ipv4Address>,
115 pub dns_servers: Vec<Ipv4Address, 3>,
117}
118
119#[cfg(feature = "proto-ipv6")]
121#[derive(Debug, Clone, PartialEq, Eq)]
122#[cfg_attr(feature = "defmt", derive(defmt::Format))]
123pub struct StaticConfigV6 {
124 pub address: Ipv6Cidr,
126 pub gateway: Option<Ipv6Address>,
128 pub dns_servers: Vec<Ipv6Address, 3>,
130}
131
132#[cfg(feature = "dhcpv4")]
134#[derive(Debug, Clone, PartialEq, Eq)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136#[non_exhaustive]
137pub struct DhcpConfig {
138 pub max_lease_duration: Option<embassy_time::Duration>,
143 pub retry_config: RetryConfig,
145 pub ignore_naks: bool,
149 pub server_port: u16,
151 pub client_port: u16,
153 #[cfg(feature = "dhcpv4-hostname")]
155 pub hostname: Option<heapless::String<MAX_HOSTNAME_LEN>>,
156}
157
158#[cfg(feature = "dhcpv4")]
159impl Default for DhcpConfig {
160 fn default() -> Self {
161 Self {
162 max_lease_duration: Default::default(),
163 retry_config: Default::default(),
164 ignore_naks: Default::default(),
165 server_port: smoltcp::wire::DHCP_SERVER_PORT,
166 client_port: smoltcp::wire::DHCP_CLIENT_PORT,
167 #[cfg(feature = "dhcpv4-hostname")]
168 hostname: None,
169 }
170 }
171}
172
173#[derive(Debug, Clone, Default, PartialEq, Eq)]
175#[cfg_attr(feature = "defmt", derive(defmt::Format))]
176#[non_exhaustive]
177pub struct Config {
178 #[cfg(feature = "proto-ipv4")]
180 pub ipv4: ConfigV4,
181 #[cfg(feature = "proto-ipv6")]
183 pub ipv6: ConfigV6,
184}
185
186impl Config {
187 #[cfg(feature = "proto-ipv4")]
189 pub const fn ipv4_static(config: StaticConfigV4) -> Self {
190 Self {
191 ipv4: ConfigV4::Static(config),
192 #[cfg(feature = "proto-ipv6")]
193 ipv6: ConfigV6::None,
194 }
195 }
196
197 #[cfg(feature = "proto-ipv6")]
199 pub const fn ipv6_static(config: StaticConfigV6) -> Self {
200 Self {
201 #[cfg(feature = "proto-ipv4")]
202 ipv4: ConfigV4::None,
203 ipv6: ConfigV6::Static(config),
204 }
205 }
206
207 #[cfg(feature = "dhcpv4")]
215 pub const fn dhcpv4(config: DhcpConfig) -> Self {
216 Self {
217 ipv4: ConfigV4::Dhcp(config),
218 #[cfg(feature = "proto-ipv6")]
219 ipv6: ConfigV6::None,
220 }
221 }
222}
223
224#[cfg(feature = "proto-ipv4")]
226#[derive(Debug, Clone, Default, PartialEq, Eq)]
227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
228pub enum ConfigV4 {
229 #[default]
231 None,
232 Static(StaticConfigV4),
234 #[cfg(feature = "dhcpv4")]
236 Dhcp(DhcpConfig),
237}
238
239#[cfg(feature = "proto-ipv6")]
241#[derive(Debug, Clone, Default, PartialEq, Eq)]
242#[cfg_attr(feature = "defmt", derive(defmt::Format))]
243pub enum ConfigV6 {
244 #[default]
246 None,
247 Static(StaticConfigV6),
249}
250
251pub struct Runner<'d, D: Driver> {
255 driver: D,
256 stack: Stack<'d>,
257}
258
259#[derive(Copy, Clone)]
264pub struct Stack<'d> {
265 inner: &'d RefCell<Inner>,
266}
267
268pub(crate) struct Inner {
269 pub(crate) sockets: SocketSet<'static>, pub(crate) iface: Interface,
271 pub(crate) waker: WakerRegistration,
273 state_waker: WakerRegistration,
275 hardware_address: HardwareAddress,
276 next_local_port: u16,
277 link_up: bool,
278 #[cfg(feature = "proto-ipv4")]
279 static_v4: Option<StaticConfigV4>,
280 #[cfg(feature = "proto-ipv6")]
281 static_v6: Option<StaticConfigV6>,
282 #[cfg(feature = "dhcpv4")]
283 dhcp_socket: Option<SocketHandle>,
284 #[cfg(feature = "dns")]
285 dns_socket: SocketHandle,
286 #[cfg(feature = "dns")]
287 dns_waker: WakerRegistration,
288 #[cfg(feature = "dhcpv4-hostname")]
289 hostname: *mut HostnameResources,
290}
291
292fn _assert_covariant<'a, 'b: 'a>(x: Stack<'b>) -> Stack<'a> {
293 x
294}
295
296pub fn new<'d, D: Driver, const SOCK: usize>(
298 mut driver: D,
299 config: Config,
300 resources: &'d mut StackResources<SOCK>,
301 random_seed: u64,
302) -> (Stack<'d>, Runner<'d, D>) {
303 let (hardware_address, medium) = to_smoltcp_hardware_address(driver.hardware_address());
304 let mut iface_cfg = smoltcp::iface::Config::new(hardware_address);
305 iface_cfg.random_seed = random_seed;
306
307 let iface = Interface::new(
308 iface_cfg,
309 &mut DriverAdapter {
310 inner: &mut driver,
311 cx: None,
312 medium,
313 },
314 instant_to_smoltcp(Instant::now()),
315 );
316
317 unsafe fn transmute_slice<T>(x: &mut [T]) -> &'static mut [T] {
318 core::mem::transmute(x)
319 }
320
321 let sockets = resources.sockets.write([SocketStorage::EMPTY; SOCK]);
322 #[allow(unused_mut)]
323 let mut sockets: SocketSet<'static> = SocketSet::new(unsafe { transmute_slice(sockets) });
324
325 let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN;
326
327 #[cfg(feature = "dns")]
328 let dns_socket = sockets.add(dns::Socket::new(
329 &[],
330 managed::ManagedSlice::Borrowed(unsafe {
331 transmute_slice(resources.queries.write([const { None }; MAX_QUERIES]))
332 }),
333 ));
334
335 let mut inner = Inner {
336 sockets,
337 iface,
338 waker: WakerRegistration::new(),
339 state_waker: WakerRegistration::new(),
340 next_local_port,
341 hardware_address,
342 link_up: false,
343 #[cfg(feature = "proto-ipv4")]
344 static_v4: None,
345 #[cfg(feature = "proto-ipv6")]
346 static_v6: None,
347 #[cfg(feature = "dhcpv4")]
348 dhcp_socket: None,
349 #[cfg(feature = "dns")]
350 dns_socket,
351 #[cfg(feature = "dns")]
352 dns_waker: WakerRegistration::new(),
353 #[cfg(feature = "dhcpv4-hostname")]
354 hostname: &mut resources.hostname,
355 };
356
357 #[cfg(feature = "proto-ipv4")]
358 inner.set_config_v4(config.ipv4);
359 #[cfg(feature = "proto-ipv6")]
360 inner.set_config_v6(config.ipv6);
361 inner.apply_static_config();
362
363 let inner = &*resources.inner.write(RefCell::new(inner));
364 let stack = Stack { inner };
365 (stack, Runner { driver, stack })
366}
367
368fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) {
369 match addr {
370 #[cfg(feature = "medium-ethernet")]
371 driver::HardwareAddress::Ethernet(eth) => (HardwareAddress::Ethernet(EthernetAddress(eth)), Medium::Ethernet),
372 #[cfg(feature = "medium-ieee802154")]
373 driver::HardwareAddress::Ieee802154(ieee) => (
374 HardwareAddress::Ieee802154(Ieee802154Address::Extended(ieee)),
375 Medium::Ieee802154,
376 ),
377 #[cfg(feature = "medium-ip")]
378 driver::HardwareAddress::Ip => (HardwareAddress::Ip, Medium::Ip),
379
380 #[allow(unreachable_patterns)]
381 _ => panic!(
382 "Unsupported medium {:?}. Make sure to enable the right medium feature in embassy-net's Cargo features.",
383 addr
384 ),
385 }
386}
387
388impl<'d> Stack<'d> {
389 fn with<R>(&self, f: impl FnOnce(&Inner) -> R) -> R {
390 f(&self.inner.borrow())
391 }
392
393 fn with_mut<R>(&self, f: impl FnOnce(&mut Inner) -> R) -> R {
394 f(&mut self.inner.borrow_mut())
395 }
396
397 pub fn hardware_address(&self) -> HardwareAddress {
399 self.with(|i| i.hardware_address)
400 }
401
402 pub fn is_link_up(&self) -> bool {
404 self.with(|i| i.link_up)
405 }
406
407 pub fn is_config_up(&self) -> bool {
410 let v4_up;
411 let v6_up;
412
413 #[cfg(feature = "proto-ipv4")]
414 {
415 v4_up = self.config_v4().is_some();
416 }
417 #[cfg(not(feature = "proto-ipv4"))]
418 {
419 v4_up = false;
420 }
421
422 #[cfg(feature = "proto-ipv6")]
423 {
424 v6_up = self.config_v6().is_some();
425 }
426 #[cfg(not(feature = "proto-ipv6"))]
427 {
428 v6_up = false;
429 }
430
431 v4_up || v6_up
432 }
433
434 pub async fn wait_link_up(&self) {
436 self.wait(|| self.is_link_up()).await
437 }
438
439 pub async fn wait_link_down(&self) {
441 self.wait(|| !self.is_link_up()).await
442 }
443
444 pub async fn wait_config_up(&self) {
474 self.wait(|| self.is_config_up()).await
475 }
476
477 pub async fn wait_config_down(&self) {
479 self.wait(|| !self.is_config_up()).await
480 }
481
482 fn wait<'a>(&'a self, mut predicate: impl FnMut() -> bool + 'a) -> impl Future<Output = ()> + 'a {
483 poll_fn(move |cx| {
484 if predicate() {
485 Poll::Ready(())
486 } else {
487 trace!("Waiting for config up");
490
491 self.with_mut(|i| {
492 i.state_waker.register(cx.waker());
493 });
494
495 Poll::Pending
496 }
497 })
498 }
499
500 #[cfg(feature = "proto-ipv4")]
505 pub fn config_v4(&self) -> Option<StaticConfigV4> {
506 self.with(|i| i.static_v4.clone())
507 }
508
509 #[cfg(feature = "proto-ipv6")]
511 pub fn config_v6(&self) -> Option<StaticConfigV6> {
512 self.with(|i| i.static_v6.clone())
513 }
514
515 #[cfg(feature = "proto-ipv4")]
517 pub fn set_config_v4(&self, config: ConfigV4) {
518 self.with_mut(|i| {
519 i.set_config_v4(config);
520 i.apply_static_config();
521 })
522 }
523
524 #[cfg(feature = "proto-ipv6")]
526 pub fn set_config_v6(&self, config: ConfigV6) {
527 self.with_mut(|i| {
528 i.set_config_v6(config);
529 i.apply_static_config();
530 })
531 }
532
533 #[cfg(feature = "dns")]
535 pub async fn dns_query(
536 &self,
537 name: &str,
538 qtype: dns::DnsQueryType,
539 ) -> Result<Vec<IpAddress, { smoltcp::config::DNS_MAX_RESULT_COUNT }>, dns::Error> {
540 match qtype {
542 #[cfg(feature = "proto-ipv4")]
543 dns::DnsQueryType::A => {
544 if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
545 return Ok([ip].into_iter().collect());
546 }
547 }
548 #[cfg(feature = "proto-ipv6")]
549 dns::DnsQueryType::Aaaa => {
550 if let Ok(ip) = name.parse().map(IpAddress::Ipv6) {
551 return Ok([ip].into_iter().collect());
552 }
553 }
554 _ => {}
555 }
556
557 let query = poll_fn(|cx| {
558 self.with_mut(|i| {
559 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
560 match socket.start_query(i.iface.context(), name, qtype) {
561 Ok(handle) => {
562 i.waker.wake();
563 Poll::Ready(Ok(handle))
564 }
565 Err(dns::StartQueryError::NoFreeSlot) => {
566 i.dns_waker.register(cx.waker());
567 Poll::Pending
568 }
569 Err(e) => Poll::Ready(Err(e)),
570 }
571 })
572 })
573 .await?;
574
575 #[must_use = "to delay the drop handler invocation to the end of the scope"]
576 struct OnDrop<F: FnOnce()> {
577 f: core::mem::MaybeUninit<F>,
578 }
579
580 impl<F: FnOnce()> OnDrop<F> {
581 fn new(f: F) -> Self {
582 Self {
583 f: core::mem::MaybeUninit::new(f),
584 }
585 }
586
587 fn defuse(self) {
588 core::mem::forget(self)
589 }
590 }
591
592 impl<F: FnOnce()> Drop for OnDrop<F> {
593 fn drop(&mut self) {
594 unsafe { self.f.as_ptr().read()() }
595 }
596 }
597
598 let drop = OnDrop::new(|| {
599 self.with_mut(|i| {
600 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
601 socket.cancel_query(query);
602 i.waker.wake();
603 i.dns_waker.wake();
604 })
605 });
606
607 let res = poll_fn(|cx| {
608 self.with_mut(|i| {
609 let socket = i.sockets.get_mut::<dns::Socket>(i.dns_socket);
610 match socket.get_query_result(query) {
611 Ok(addrs) => {
612 i.dns_waker.wake();
613 Poll::Ready(Ok(addrs))
614 }
615 Err(dns::GetQueryResultError::Pending) => {
616 socket.register_query_waker(query, cx.waker());
617 Poll::Pending
618 }
619 Err(e) => {
620 i.dns_waker.wake();
621 Poll::Ready(Err(e.into()))
622 }
623 }
624 })
625 })
626 .await;
627
628 drop.defuse();
629
630 res
631 }
632}
633
634#[cfg(feature = "multicast")]
635impl<'d> Stack<'d> {
636 pub fn join_multicast_group(&self, addr: impl Into<IpAddress>) -> Result<(), MulticastError> {
638 self.with_mut(|i| i.iface.join_multicast_group(addr))
639 }
640
641 pub fn leave_multicast_group(&self, addr: impl Into<IpAddress>) -> Result<(), MulticastError> {
643 self.with_mut(|i| i.iface.leave_multicast_group(addr))
644 }
645
646 pub fn has_multicast_group(&self, addr: impl Into<IpAddress>) -> bool {
648 self.with(|i| i.iface.has_multicast_group(addr))
649 }
650}
651
652impl Inner {
653 #[allow(clippy::absurd_extreme_comparisons)]
654 pub fn get_local_port(&mut self) -> u16 {
655 let res = self.next_local_port;
656 self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 };
657 res
658 }
659
660 #[cfg(feature = "proto-ipv4")]
661 pub fn set_config_v4(&mut self, config: ConfigV4) {
662 self.static_v4 = match config.clone() {
664 ConfigV4::None => None,
665 #[cfg(feature = "dhcpv4")]
666 ConfigV4::Dhcp(_) => None,
667 ConfigV4::Static(c) => Some(c),
668 };
669
670 #[cfg(feature = "dhcpv4")]
672 match config {
673 ConfigV4::Dhcp(c) => {
674 if self.dhcp_socket.is_none() {
676 let socket = smoltcp::socket::dhcpv4::Socket::new();
677 let handle = self.sockets.add(socket);
678 self.dhcp_socket = Some(handle);
679 }
680
681 let socket = self.sockets.get_mut::<dhcpv4::Socket>(unwrap!(self.dhcp_socket));
683 socket.set_ignore_naks(c.ignore_naks);
684 socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp));
685 socket.set_ports(c.server_port, c.client_port);
686 socket.set_retry_config(c.retry_config);
687
688 socket.set_outgoing_options(&[]);
689 #[cfg(feature = "dhcpv4-hostname")]
690 if let Some(h) = c.hostname {
691 let hostname = unsafe { &mut *self.hostname };
696
697 let data = hostname.data.write([0; MAX_HOSTNAME_LEN]);
699 data[..h.len()].copy_from_slice(h.as_bytes());
700 let data: &[u8] = &data[..h.len()];
701
702 let option = hostname.option.write(smoltcp::wire::DhcpOption { data, kind: 12 });
704 socket.set_outgoing_options(core::slice::from_ref(option));
705 }
706
707 socket.reset();
708 }
709 _ => {
710 if let Some(socket) = self.dhcp_socket {
712 self.sockets.remove(socket);
713 self.dhcp_socket = None;
714 }
715 }
716 }
717 }
718
719 #[cfg(feature = "proto-ipv6")]
720 pub fn set_config_v6(&mut self, config: ConfigV6) {
721 self.static_v6 = match config {
722 ConfigV6::None => None,
723 ConfigV6::Static(c) => Some(c),
724 };
725 }
726
727 fn apply_static_config(&mut self) {
728 let mut addrs = Vec::new();
729 #[cfg(feature = "dns")]
730 let mut dns_servers: Vec<_, 6> = Vec::new();
731 #[cfg(feature = "proto-ipv4")]
732 let mut gateway_v4 = None;
733 #[cfg(feature = "proto-ipv6")]
734 let mut gateway_v6 = None;
735
736 #[cfg(feature = "proto-ipv4")]
737 if let Some(config) = &self.static_v4 {
738 debug!("IPv4: UP");
739 debug!(" IP address: {:?}", config.address);
740 debug!(" Default gateway: {:?}", config.gateway);
741
742 unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok());
743 gateway_v4 = config.gateway;
744 #[cfg(feature = "dns")]
745 for s in &config.dns_servers {
746 debug!(" DNS server: {:?}", s);
747 unwrap!(dns_servers.push(s.clone().into()).ok());
748 }
749 } else {
750 info!("IPv4: DOWN");
751 }
752
753 #[cfg(feature = "proto-ipv6")]
754 if let Some(config) = &self.static_v6 {
755 debug!("IPv6: UP");
756 debug!(" IP address: {:?}", config.address);
757 debug!(" Default gateway: {:?}", config.gateway);
758
759 unwrap!(addrs.push(IpCidr::Ipv6(config.address)).ok());
760 gateway_v6 = config.gateway.into();
761 #[cfg(feature = "dns")]
762 for s in &config.dns_servers {
763 debug!(" DNS server: {:?}", s);
764 unwrap!(dns_servers.push(s.clone().into()).ok());
765 }
766 } else {
767 info!("IPv6: DOWN");
768 }
769
770 self.iface.update_ip_addrs(|a| *a = addrs);
772
773 #[cfg(feature = "proto-ipv4")]
775 if let Some(gateway) = gateway_v4 {
776 unwrap!(self.iface.routes_mut().add_default_ipv4_route(gateway));
777 } else {
778 self.iface.routes_mut().remove_default_ipv4_route();
779 }
780 #[cfg(feature = "proto-ipv6")]
781 if let Some(gateway) = gateway_v6 {
782 unwrap!(self.iface.routes_mut().add_default_ipv6_route(gateway));
783 } else {
784 self.iface.routes_mut().remove_default_ipv6_route();
785 }
786
787 #[cfg(feature = "dns")]
789 if !dns_servers.is_empty() {
790 let count = if dns_servers.len() > DNS_MAX_SERVER_COUNT {
791 warn!("Number of DNS servers exceeds DNS_MAX_SERVER_COUNT, truncating list.");
792 DNS_MAX_SERVER_COUNT
793 } else {
794 dns_servers.len()
795 };
796 self.sockets
797 .get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
798 .update_servers(&dns_servers[..count]);
799 }
800
801 self.state_waker.wake();
802 }
803
804 fn poll<D: Driver>(&mut self, cx: &mut Context<'_>, driver: &mut D) {
805 self.waker.register(cx.waker());
806
807 let (_hardware_addr, medium) = to_smoltcp_hardware_address(driver.hardware_address());
808
809 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
810 {
811 let do_set = match medium {
812 #[cfg(feature = "medium-ethernet")]
813 Medium::Ethernet => true,
814 #[cfg(feature = "medium-ieee802154")]
815 Medium::Ieee802154 => true,
816 #[allow(unreachable_patterns)]
817 _ => false,
818 };
819 if do_set {
820 self.iface.set_hardware_addr(_hardware_addr);
821 }
822 }
823
824 let timestamp = instant_to_smoltcp(Instant::now());
825 let mut smoldev = DriverAdapter {
826 cx: Some(cx),
827 inner: driver,
828 medium,
829 };
830 self.iface.poll(timestamp, &mut smoldev, &mut self.sockets);
831
832 let old_link_up = self.link_up;
834 self.link_up = driver.link_state(cx) == LinkState::Up;
835
836 if old_link_up != self.link_up {
838 info!("link_up = {:?}", self.link_up);
839 self.state_waker.wake();
840 }
841
842 #[cfg(feature = "dhcpv4")]
843 if let Some(dhcp_handle) = self.dhcp_socket {
844 let socket = self.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
845
846 let configure = if self.link_up {
847 if old_link_up != self.link_up {
848 socket.reset();
849 }
850 match socket.poll() {
851 None => false,
852 Some(dhcpv4::Event::Deconfigured) => {
853 self.static_v4 = None;
854 true
855 }
856 Some(dhcpv4::Event::Configured(config)) => {
857 self.static_v4 = Some(StaticConfigV4 {
858 address: config.address,
859 gateway: config.router,
860 dns_servers: config.dns_servers,
861 });
862 true
863 }
864 }
865 } else if old_link_up {
866 socket.reset();
867 self.static_v4 = None;
868 true
869 } else {
870 false
871 };
872 if configure {
873 self.apply_static_config()
874 }
875 }
876
877 if let Some(poll_at) = self.iface.poll_at(timestamp, &mut self.sockets) {
878 let t = pin!(Timer::at(instant_from_smoltcp(poll_at)));
879 if t.poll(cx).is_ready() {
880 cx.waker().wake_by_ref();
881 }
882 }
883 }
884}
885
886impl<'d, D: Driver> Runner<'d, D> {
887 pub async fn run(&mut self) -> ! {
891 poll_fn(|cx| {
892 self.stack.with_mut(|i| i.poll(cx, &mut self.driver));
893 Poll::<()>::Pending
894 })
895 .await;
896 unreachable!()
897 }
898}