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