From cc8961034e53d4fc2ac4539096c2a67059eb60b7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 19:48:45 +0200 Subject: net: allow changing IP config at runtime. --- embassy-net/src/lib.rs | 320 +++++++++++++++++++++++-------------------------- 1 file changed, 148 insertions(+), 172 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 2fb34f43a..9f8812894 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -3,6 +3,9 @@ #![warn(missing_docs)] #![doc = include_str!("../README.md")] +#[cfg(not(any(feature = "proto-ipv4", feature = "proto-ipv6")))] +compile_error!("You must enable at least one of the following features: proto-ipv4, proto-ipv6"); + // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -20,7 +23,7 @@ use core::future::{poll_fn, Future}; use core::task::{Context, Poll}; pub use embassy_net_driver as driver; -use embassy_net_driver::{Driver, LinkState, Medium}; +use embassy_net_driver::{Driver, LinkState}; use embassy_sync::waitqueue::WakerRegistration; use embassy_time::{Instant, Timer}; use futures::pin_mut; @@ -133,6 +136,8 @@ impl Default for DhcpConfig { } /// Network stack configuration. +#[derive(Debug, Clone, Default)] +#[non_exhaustive] pub struct Config { /// IPv4 configuration #[cfg(feature = "proto-ipv4")] @@ -181,23 +186,27 @@ impl Config { /// Network stack IPv4 configuration. #[cfg(feature = "proto-ipv4")] +#[derive(Debug, Clone, Default)] pub enum ConfigV4 { + /// Do not configure IPv4. + #[default] + None, /// Use a static IPv4 address configuration. Static(StaticConfigV4), /// Use DHCP to obtain an IP address configuration. #[cfg(feature = "dhcpv4")] Dhcp(DhcpConfig), - /// Do not configure IPv6. - None, } /// Network stack IPv6 configuration. #[cfg(feature = "proto-ipv6")] +#[derive(Debug, Clone, Default)] pub enum ConfigV6 { - /// Use a static IPv6 address configuration. - Static(StaticConfigV6), /// Do not configure IPv6. + #[default] None, + /// Use a static IPv6 address configuration. + Static(StaticConfigV6), } /// A network stack. @@ -276,7 +285,6 @@ impl Stack { next_local_port, }; - #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))] let mut inner = Inner { device, link_up: false, @@ -295,30 +303,11 @@ impl Stack { dns_waker: WakerRegistration::new(), }; - #[cfg(feature = "medium-ieee802154")] - let _ = config; - #[cfg(feature = "proto-ipv4")] - match config.ipv4 { - ConfigV4::Static(config) => { - inner.apply_config_v4(&mut socket, config); - } - #[cfg(feature = "dhcpv4")] - ConfigV4::Dhcp(config) => { - let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); - inner.apply_dhcp_config(&mut dhcp_socket, config); - let handle = socket.sockets.add(dhcp_socket); - inner.dhcp_socket = Some(handle); - } - ConfigV4::None => {} - } + inner.set_config_v4(&mut socket, config.ipv4); #[cfg(feature = "proto-ipv6")] - match config.ipv6 { - ConfigV6::Static(config) => { - inner.apply_config_v6(&mut socket, config); - } - ConfigV6::None => {} - } + inner.set_config_v6(&mut socket, config.ipv6); + inner.apply_static_config(&mut socket); Self { socket: RefCell::new(socket), @@ -372,15 +361,36 @@ impl Stack { } /// Get the current IPv4 configuration. + /// + /// If using DHCP, this will be None if DHCP hasn't been able to + /// acquire an IP address, or Some if it has. #[cfg(feature = "proto-ipv4")] pub fn config_v4(&self) -> Option { - self.with(|_s, i| i.static_v4.clone()) + self.with(|_, i| i.static_v4.clone()) } /// Get the current IPv6 configuration. #[cfg(feature = "proto-ipv6")] pub fn config_v6(&self) -> Option { - self.with(|_s, i| i.static_v6.clone()) + self.with(|_, i| i.static_v6.clone()) + } + + /// Set the IPv4 configuration. + #[cfg(feature = "proto-ipv4")] + pub fn set_config_v4(&self, config: ConfigV4) { + self.with_mut(|s, i| { + i.set_config_v4(s, config); + i.apply_static_config(s); + }) + } + + /// Set the IPv6 configuration. + #[cfg(feature = "proto-ipv6")] + pub fn set_config_v6(&self, config: ConfigV6) { + self.with_mut(|s, i| { + i.set_config_v6(s, config); + i.apply_static_config(s); + }) } /// Run the network stack. @@ -582,166 +592,125 @@ impl SocketStack { impl Inner { #[cfg(feature = "proto-ipv4")] - fn apply_config_v4(&mut self, s: &mut SocketStack, config: StaticConfigV4) { - debug!("Acquired IP configuration:"); - - debug!(" IP address: {}", config.address); - s.iface.update_ip_addrs(|addrs| { - if let Some((index, _)) = addrs - .iter() - .enumerate() - .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_))) - { - addrs.remove(index); - } - addrs.push(IpCidr::Ipv4(config.address)).unwrap(); - }); - - #[cfg(feature = "medium-ip")] - let skip_gateway = self.device.capabilities().medium != Medium::Ip; - #[cfg(not(feature = "medium-ip"))] - let skip_gateway = false; - - if !skip_gateway { - if let Some(gateway) = config.gateway { - debug!(" Default gateway: {}", gateway); - s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); - } else { - debug!(" Default gateway: None"); - s.iface.routes_mut().remove_default_ipv4_route(); - } - } - for (i, s) in config.dns_servers.iter().enumerate() { - debug!(" DNS server {}: {}", i, s); - } + pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) { + // Handle static config. + self.static_v4 = match config.clone() { + ConfigV4::None => None, + #[cfg(feature = "dhcpv4")] + ConfigV4::Dhcp(_) => None, + ConfigV4::Static(c) => Some(c), + }; - self.static_v4 = Some(config); + // Handle DHCP config. + #[cfg(feature = "dhcpv4")] + match config { + ConfigV4::Dhcp(c) => { + // Create the socket if it doesn't exist. + if self.dhcp_socket.is_none() { + let socket = smoltcp::socket::dhcpv4::Socket::new(); + let handle = _s.sockets.add(socket); + self.dhcp_socket = Some(handle); + } - #[cfg(feature = "dns")] - { - self.update_dns_servers(s) + // Configure it + let socket = _s.sockets.get_mut::(self.dhcp_socket.unwrap()); + socket.set_ignore_naks(c.ignore_naks); + socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); + socket.set_ports(c.server_port, c.client_port); + socket.set_retry_config(c.retry_config); + socket.reset(); + } + _ => { + // Remove DHCP socket if any. + if let Some(socket) = self.dhcp_socket { + _s.sockets.remove(socket); + self.dhcp_socket = None; + } + } } } - /// Replaces the current IPv6 static configuration with a newly supplied config. #[cfg(feature = "proto-ipv6")] - fn apply_config_v6(&mut self, s: &mut SocketStack, config: StaticConfigV6) { - #[cfg(feature = "medium-ethernet")] - let medium = self.device.capabilities().medium; + pub fn set_config_v6(&mut self, _s: &mut SocketStack, config: ConfigV6) { + self.static_v6 = match config { + ConfigV6::None => None, + ConfigV6::Static(c) => Some(c), + }; + } - debug!("Acquired IPv6 configuration:"); + fn apply_static_config(&mut self, s: &mut SocketStack) { + let mut addrs = Vec::new(); + #[cfg(feature = "dns")] + let mut dns_servers: Vec<_, 6> = Vec::new(); + #[cfg(feature = "proto-ipv4")] + let mut gateway_v4 = None; + #[cfg(feature = "proto-ipv6")] + let mut gateway_v6 = None; - debug!(" IP address: {}", config.address); - s.iface.update_ip_addrs(|addrs| { - if let Some((index, _)) = addrs - .iter() - .enumerate() - .find(|(_, &addr)| matches!(addr, IpCidr::Ipv6(_))) - { - addrs.remove(index); - } - addrs.push(IpCidr::Ipv6(config.address)).unwrap(); - }); + #[cfg(feature = "proto-ipv4")] + if let Some(config) = &self.static_v4 { + debug!("IPv4: UP"); + debug!(" IP address: {:?}", config.address); + debug!(" Default gateway: {:?}", config.gateway); - #[cfg(feature = "medium-ethernet")] - if Medium::Ethernet == medium { - if let Some(gateway) = config.gateway { - debug!(" Default gateway: {}", gateway); - s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); - } else { - debug!(" Default gateway: None"); - s.iface.routes_mut().remove_default_ipv6_route(); + addrs.push(IpCidr::Ipv4(config.address)).unwrap(); + gateway_v4 = config.gateway.into(); + #[cfg(feature = "dns")] + for s in &config.dns_servers { + debug!(" DNS server: {:?}", s); + dns_servers.push(s.clone().into()).unwrap(); } - } - for (i, s) in config.dns_servers.iter().enumerate() { - debug!(" DNS server {}: {}", i, s); + } else { + info!("IPv4: DOWN"); } - self.static_v6 = Some(config); + #[cfg(feature = "proto-ipv6")] + if let Some(config) = &self.static_v6 { + debug!("IPv6: UP"); + debug!(" IP address: {:?}", config.address); + debug!(" Default gateway: {:?}", config.gateway); - #[cfg(feature = "dns")] - { - self.update_dns_servers(s) + addrs.push(IpCidr::Ipv6(config.address)).unwrap(); + gateway_v6 = config.gateway.into(); + #[cfg(feature = "dns")] + for s in &config.dns_servers { + debug!(" DNS server: {:?}", s); + dns_servers.push(s.clone().into()).unwrap(); + } + } else { + info!("IPv6: DOWN"); } - } - #[cfg(feature = "dns")] - fn update_dns_servers(&mut self, s: &mut SocketStack) { - let socket = s.sockets.get_mut::(self.dns_socket); + // Apply addresses + s.iface.update_ip_addrs(|a| *a = addrs); - let servers_v4; + // Apply gateways #[cfg(feature = "proto-ipv4")] - { - servers_v4 = self - .static_v4 - .iter() - .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv4(*c))); - }; - #[cfg(not(feature = "proto-ipv4"))] - { - servers_v4 = core::iter::empty(); + if let Some(gateway) = gateway_v4 { + s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); + } else { + s.iface.routes_mut().remove_default_ipv4_route(); } - - let servers_v6; #[cfg(feature = "proto-ipv6")] - { - servers_v6 = self - .static_v6 - .iter() - .flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv6(*c))); + if let Some(gateway) = gateway_v6 { + s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); + } else { + s.iface.routes_mut().remove_default_ipv6_route(); } - #[cfg(not(feature = "proto-ipv6"))] - { - servers_v6 = core::iter::empty(); - } - - // Prefer the v6 DNS servers over the v4 servers - let servers: Vec = servers_v6.chain(servers_v4).collect(); - socket.update_servers(&servers[..]); - } - #[cfg(feature = "dhcpv4")] - fn apply_dhcp_config(&self, socket: &mut smoltcp::socket::dhcpv4::Socket, config: DhcpConfig) { - socket.set_ignore_naks(config.ignore_naks); - socket.set_max_lease_duration(config.max_lease_duration.map(crate::time::duration_to_smoltcp)); - socket.set_ports(config.server_port, config.client_port); - socket.set_retry_config(config.retry_config); - } - - #[cfg(feature = "dhcpv4")] - fn unapply_config_v4(&mut self, s: &mut SocketStack) { - #[cfg(feature = "medium-ethernet")] - let medium = self.device.capabilities().medium; - debug!("Lost IP configuration"); - s.iface.update_ip_addrs(|ip_addrs| { - #[cfg(feature = "proto-ipv4")] - if let Some((index, _)) = ip_addrs - .iter() - .enumerate() - .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_))) - { - ip_addrs.remove(index); - } - }); - #[cfg(feature = "medium-ethernet")] - if medium == Medium::Ethernet { - #[cfg(feature = "proto-ipv4")] - { - s.iface.routes_mut().remove_default_ipv4_route(); - } - } - #[cfg(feature = "proto-ipv4")] - { - self.static_v4 = None - } + // Apply DNS servers + #[cfg(feature = "dns")] + s.sockets + .get_mut::(self.dns_socket) + .update_servers(&dns_servers[..]); } fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { s.waker.register(cx.waker()); #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] - if self.device.capabilities().medium == Medium::Ethernet - || self.device.capabilities().medium == Medium::Ieee802154 + if self.device.capabilities().medium == embassy_net_driver::Medium::Ethernet + || self.device.capabilities().medium == embassy_net_driver::Medium::Ieee802154 { s.iface .set_hardware_addr(to_smoltcp_hardware_address(self.device.hardware_address())); @@ -763,6 +732,9 @@ impl Inner { info!("link_up = {:?}", self.link_up); } + #[allow(unused_mut)] + let mut apply_config = false; + #[cfg(feature = "dhcpv4")] if let Some(dhcp_handle) = self.dhcp_socket { let socket = s.sockets.get_mut::(dhcp_handle); @@ -770,25 +742,29 @@ impl Inner { if self.link_up { match socket.poll() { None => {} - Some(dhcpv4::Event::Deconfigured) => self.unapply_config_v4(s), + Some(dhcpv4::Event::Deconfigured) => { + self.static_v4 = None; + apply_config = true; + } Some(dhcpv4::Event::Configured(config)) => { - let config = StaticConfigV4 { + self.static_v4 = Some(StaticConfigV4 { address: config.address, gateway: config.router, dns_servers: config.dns_servers, - }; - self.apply_config_v4(s, config) + }); + apply_config = true; } } } else if old_link_up { socket.reset(); - self.unapply_config_v4(s); + self.static_v4 = None; + apply_config = true; } } - //if old_link_up || self.link_up { - // self.poll_configurator(timestamp) - //} - // + + if apply_config { + self.apply_static_config(s); + } if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { let t = Timer::at(instant_from_smoltcp(poll_at)); -- cgit From b5748524f86f809d9c8dc2c5b4bb3f07e55dbda1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Aug 2023 01:03:24 +0200 Subject: net: improve error message on unsupported medium. --- embassy-net/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 9f8812894..3a385fad6 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -249,7 +249,10 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress driver::HardwareAddress::Ip => HardwareAddress::Ip, #[allow(unreachable_patterns)] - _ => panic!("Unsupported address {:?}. Make sure to enable medium-ethernet or medium-ieee802154 in embassy-net's Cargo features.", addr), + _ => panic!( + "Unsupported medium {:?}. Make sure to enable the right medium feature in embassy-net's Cargo features.", + addr + ), } } -- cgit From 5e613d9abbb945e7fc7d4c895d645bfad6a3d2c8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 30 Aug 2023 01:37:18 +0200 Subject: Sync all fmt.rs files. --- embassy-net/src/fmt.rs | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/fmt.rs b/embassy-net/src/fmt.rs index 066970813..78e583c1c 100644 --- a/embassy-net/src/fmt.rs +++ b/embassy-net/src/fmt.rs @@ -1,6 +1,8 @@ #![macro_use] #![allow(unused_macros)] +use core::fmt::{Debug, Display, LowerHex}; + #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); @@ -81,14 +83,17 @@ macro_rules! todo { }; } +#[cfg(not(feature = "defmt"))] macro_rules! unreachable { ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) }; } @@ -223,3 +228,31 @@ impl Try for Result { self } } + +#[allow(unused)] +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} -- cgit From 0c66636d003979c3aecff36c9e03e87f34147a94 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Sat, 2 Sep 2023 07:44:10 +0200 Subject: Use fmt::unwrap --- embassy-net/src/device.rs | 4 ++-- embassy-net/src/lib.rs | 14 +++++++------- embassy-net/src/tcp.rs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index d29ab8970..8c2b7d31a 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -22,13 +22,13 @@ where fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { self.inner - .receive(self.cx.as_deref_mut().unwrap()) + .receive(unwrap!(self.cx.as_deref_mut())) .map(|(rx, tx)| (RxTokenAdapter(rx), TxTokenAdapter(tx))) } /// Construct a transmit token. fn transmit(&mut self, _timestamp: Instant) -> Option> { - self.inner.transmit(self.cx.as_deref_mut().unwrap()).map(TxTokenAdapter) + self.inner.transmit(unwrap!(self.cx.as_deref_mut())).map(TxTokenAdapter) } /// Get a description of device capabilities. diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 3a385fad6..c2575267c 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -616,7 +616,7 @@ impl Inner { } // Configure it - let socket = _s.sockets.get_mut::(self.dhcp_socket.unwrap()); + let socket = _s.sockets.get_mut::(unwrap!(self.dhcp_socket)); socket.set_ignore_naks(c.ignore_naks); socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); socket.set_ports(c.server_port, c.client_port); @@ -656,12 +656,12 @@ impl Inner { debug!(" IP address: {:?}", config.address); debug!(" Default gateway: {:?}", config.gateway); - addrs.push(IpCidr::Ipv4(config.address)).unwrap(); + unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok()); gateway_v4 = config.gateway.into(); #[cfg(feature = "dns")] for s in &config.dns_servers { debug!(" DNS server: {:?}", s); - dns_servers.push(s.clone().into()).unwrap(); + unwrap!(dns_servers.push(s.clone().into()).ok()); } } else { info!("IPv4: DOWN"); @@ -673,12 +673,12 @@ impl Inner { debug!(" IP address: {:?}", config.address); debug!(" Default gateway: {:?}", config.gateway); - addrs.push(IpCidr::Ipv6(config.address)).unwrap(); + unwrap!(addrs.push(IpCidr::Ipv6(config.address)).ok()); gateway_v6 = config.gateway.into(); #[cfg(feature = "dns")] for s in &config.dns_servers { debug!(" DNS server: {:?}", s); - dns_servers.push(s.clone().into()).unwrap(); + unwrap!(dns_servers.push(s.clone().into()).ok()); } } else { info!("IPv6: DOWN"); @@ -690,13 +690,13 @@ impl Inner { // Apply gateways #[cfg(feature = "proto-ipv4")] if let Some(gateway) = gateway_v4 { - s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); + unwrap!(s.iface.routes_mut().add_default_ipv4_route(gateway)); } else { s.iface.routes_mut().remove_default_ipv4_route(); } #[cfg(feature = "proto-ipv6")] if let Some(gateway) = gateway_v6 { - s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap(); + unwrap!(s.iface.routes_mut().add_default_ipv6_route(gateway)); } else { s.iface.routes_mut().remove_default_ipv6_route(); } diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index c92ad2d2e..a12fd382a 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -440,7 +440,7 @@ impl<'d> TcpIo<'d> { Poll::Ready(Err(Error::ConnectionReset)) } } else { - Poll::Ready(match s.send(f.take().unwrap()) { + Poll::Ready(match s.send(unwrap!(f.take())) { // Connection reset. TODO: this can also be timeouts etc, investigate. Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset), Ok(r) => Ok(r), @@ -468,7 +468,7 @@ impl<'d> TcpIo<'d> { Poll::Ready(Err(Error::ConnectionReset)) } } else { - Poll::Ready(match s.recv(f.take().unwrap()) { + Poll::Ready(match s.recv(unwrap!(f.take())) { // Connection reset. TODO: this can also be timeouts etc, investigate. Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => { Err(Error::ConnectionReset) -- cgit From a4f8d82ef51b7c0c775168472829ecd18d8f84d8 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:58:47 +0200 Subject: wait_config_up first steps --- embassy-net/src/lib.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index c2575267c..8289ecddf 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -226,6 +226,7 @@ struct Inner { static_v6: Option, #[cfg(feature = "dhcpv4")] dhcp_socket: Option, + config_waker: WakerRegistration, #[cfg(feature = "dns")] dns_socket: SocketHandle, #[cfg(feature = "dns")] @@ -297,6 +298,7 @@ impl Stack { static_v6: None, #[cfg(feature = "dhcpv4")] dhcp_socket: None, + config_waker: WakerRegistration::new(), #[cfg(feature = "dns")] dns_socket: socket.sockets.add(dns::Socket::new( &[], @@ -363,6 +365,28 @@ impl Stack { v4_up || v6_up } + /// Get for the network stack to obtainer a valid IP configuration. + pub async fn wait_config_up(&self) { + if self.is_config_up() { + return; + } + + poll_fn(|cx| { + self.with_mut(|_, i| { + debug!("poll_fn called"); + if self.is_config_up() { + debug!("poll_fn ready"); + Poll::Ready(()) + } else { + debug!("poll_fn pending"); + i.config_waker.register(cx.waker()); + Poll::Pending + } + }) + }) + .await; + } + /// Get the current IPv4 configuration. /// /// If using DHCP, this will be None if DHCP hasn't been able to @@ -706,6 +730,8 @@ impl Inner { s.sockets .get_mut::(self.dns_socket) .update_servers(&dns_servers[..]); + + s.waker.wake(); } fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { -- cgit From 6070d61d8ce2d9ce416467ac6aac8ffdd89a59b9 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:59:46 +0200 Subject: fix typos --- embassy-net/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 8289ecddf..9eea8cb4e 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -365,7 +365,7 @@ impl Stack { v4_up || v6_up } - /// Get for the network stack to obtainer a valid IP configuration. + /// Wait for the network stack to obtaine a valid IP configuration. pub async fn wait_config_up(&self) { if self.is_config_up() { return; -- cgit From 3e0b752befd492229bfb4c6f9fd3213cfd69a0fc Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 8 Sep 2023 17:26:01 +0200 Subject: fix poll_fn, add documentation --- embassy-net/src/lib.rs | 53 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 12 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 9eea8cb4e..4922490d9 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -172,6 +172,7 @@ impl Config { /// /// # Example /// ```rust + /// # use embassy_net::Config; /// let _cfg = Config::dhcpv4(Default::default()); /// ``` #[cfg(feature = "dhcpv4")] @@ -365,24 +366,52 @@ impl Stack { v4_up || v6_up } - /// Wait for the network stack to obtaine a valid IP configuration. + /// Wait for the network stack to obtain a valid IP configuration. + /// Returns instantly if [`Stack::is_config_up`] returns `true`. + /// + /// ## Watch out: + /// The Future is polled only when the [`Stack`] is running, + /// e.g. call `spawner.spawn(net_task(stack))`. + /// + /// `await`ing before will never yield! + /// + /// ## Example + /// ```ignore + /// let config = embassy_net::Config::dhcpv4(Default::default()); + ///// Init network stack + /// let stack = &*make_static!(embassy_net::Stack::new( + /// device, + /// config, + /// make_static!(embassy_net::StackResources::<2>::new()), + /// seed + /// )); + /// // Launch network task + /// spawner.spawn(net_task(stack)).unwrap(); + /// // Wait for DHCP config + /// stack.wait_config_up().await; + /// // use the network stack + /// // ... + /// ``` pub async fn wait_config_up(&self) { + // If the config is up already, we can return immediately. if self.is_config_up() { return; } poll_fn(|cx| { - self.with_mut(|_, i| { - debug!("poll_fn called"); - if self.is_config_up() { - debug!("poll_fn ready"); - Poll::Ready(()) - } else { - debug!("poll_fn pending"); + if self.is_config_up() { + Poll::Ready(()) + } else { + // If the config is not up, we register a waker that is woken up + // when a config is applied (static or DHCP). + trace!("Waiting for config up"); + + self.with_mut(|_, i| { i.config_waker.register(cx.waker()); - Poll::Pending - } - }) + }); + + Poll::Pending + } }) .await; } @@ -731,7 +760,7 @@ impl Inner { .get_mut::(self.dns_socket) .update_servers(&dns_servers[..]); - s.waker.wake(); + self.config_waker.wake(); } fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { -- cgit From 40a18b075dc80048233c54f5cff80658405a9050 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sat, 9 Sep 2023 09:50:24 +0200 Subject: improve docstring --- embassy-net/src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 4922490d9..87247c8e1 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -367,13 +367,12 @@ impl Stack { } /// Wait for the network stack to obtain a valid IP configuration. - /// Returns instantly if [`Stack::is_config_up`] returns `true`. /// - /// ## Watch out: - /// The Future is polled only when the [`Stack`] is running, - /// e.g. call `spawner.spawn(net_task(stack))`. + /// ## Notes: + /// - Ensure [`Stack::run`] has been called before using this function. /// - /// `await`ing before will never yield! + /// - This function may never yield (e.g. if no configuration is obtained through DHCP). + /// The caller is supposed to handle a timeout for this case. /// /// ## Example /// ```ignore @@ -385,7 +384,7 @@ impl Stack { /// make_static!(embassy_net::StackResources::<2>::new()), /// seed /// )); - /// // Launch network task + /// // Launch network task that runs `stack.run().await` /// spawner.spawn(net_task(stack)).unwrap(); /// // Wait for DHCP config /// stack.wait_config_up().await; -- cgit From 0e9131fd1465d8fc765c4da05ce63d9dfbf950c7 Mon Sep 17 00:00:00 2001 From: Julian <20155974+JuliDi@users.noreply.github.com> Date: Sat, 9 Sep 2023 12:36:57 +0200 Subject: yield -> return Co-authored-by: Dario Nieuwenhuis --- embassy-net/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 87247c8e1..de32edc2f 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -371,7 +371,7 @@ impl Stack { /// ## Notes: /// - Ensure [`Stack::run`] has been called before using this function. /// - /// - This function may never yield (e.g. if no configuration is obtained through DHCP). + /// - This function may never return (e.g. if no configuration is obtained through DHCP). /// The caller is supposed to handle a timeout for this case. /// /// ## Example -- cgit From d6a1b567ee1eeaa98f9e8938227c0f3be3559670 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:13:56 +0200 Subject: add SocketNotBound error message --- embassy-net/src/udp.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 0a5a7b8f6..61058c1ba 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -29,6 +29,8 @@ pub enum BindError { pub enum Error { /// No route to host. NoRoute, + /// Socket not bound to an outgoing port. + SocketNotBound, } /// An UDP socket. @@ -155,7 +157,14 @@ impl<'a> UdpSocket<'a> { s.register_send_waker(cx.waker()); Poll::Pending } - Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)), + Err(udp::SendError::Unaddressable) => { + // If no sender/outgoing port is specified, there is not really "no route" + if s.endpoint().port == 0 { + Poll::Ready(Err(Error::SocketNotBound)) + } else { + Poll::Ready(Err(Error::NoRoute)) + } + } }) } -- cgit From 7bcc7e89620c5aac197207bb6d646e0e19ff6972 Mon Sep 17 00:00:00 2001 From: Polly Date: Thu, 14 Sep 2023 16:08:37 +0200 Subject: Fix doc typo --- embassy-net/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index de32edc2f..f48d3372e 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -168,7 +168,7 @@ impl Config { } } - /// IPv6 configuration with dynamic addressing. + /// IPv4 configuration with dynamic addressing. /// /// # Example /// ```rust -- cgit From 901f0257bd4b64d6ed846de701a0b71b1de4b16d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Sep 2023 03:46:48 +0200 Subject: net: allow non-'static drivers. --- embassy-net/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index f48d3372e..0d7ac47a2 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -258,7 +258,7 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress } } -impl Stack { +impl Stack { /// Create a new network stack. pub fn new( mut device: D, @@ -555,7 +555,7 @@ impl Stack { } #[cfg(feature = "igmp")] -impl Stack { +impl Stack { /// Join a multicast group. pub async fn join_multicast_group(&self, addr: T) -> Result where @@ -645,7 +645,7 @@ impl SocketStack { } } -impl Inner { +impl Inner { #[cfg(feature = "proto-ipv4")] pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) { // Handle static config. -- cgit