From cb5931d583d283dda3a1b5ed2014c086bb8f98ae Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 3 Feb 2021 05:09:37 +0100 Subject: :rainbow: --- embassy-net/src/stack.rs | 212 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 embassy-net/src/stack.rs (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs new file mode 100644 index 000000000..c353f1bb1 --- /dev/null +++ b/embassy-net/src/stack.rs @@ -0,0 +1,212 @@ +use core::future::Future; +use core::task::Context; +use core::task::Poll; +use core::{cell::RefCell, future}; +use embassy::time::{Instant, Timer}; +use embassy::util::ThreadModeMutex; +use embassy::util::{Forever, WakerRegistration}; +use futures::pin_mut; +use smoltcp::iface::{InterfaceBuilder, Neighbor, NeighborCache, Route, Routes}; +use smoltcp::phy::Device as _; +use smoltcp::phy::Medium; +use smoltcp::socket::SocketSetItem; +use smoltcp::time::Instant as SmolInstant; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; + +use crate::device::{Device, DeviceAdapter}; +use crate::fmt::*; +use crate::{ + config::{Config, Configurator}, + device::LinkState, +}; +use crate::{Interface, SocketSet}; + +const ADDRESSES_LEN: usize = 1; +const NEIGHBOR_CACHE_LEN: usize = 8; +const SOCKETS_LEN: usize = 2; +const LOCAL_PORT_MIN: u16 = 1025; +const LOCAL_PORT_MAX: u16 = 65535; + +struct StackResources { + addresses: [IpCidr; ADDRESSES_LEN], + neighbor_cache: [Option<(IpAddress, Neighbor)>; NEIGHBOR_CACHE_LEN], + sockets: [Option>; SOCKETS_LEN], + routes: [Option<(IpCidr, Route)>; 1], +} + +static STACK_RESOURCES: Forever = Forever::new(); +static STACK: ThreadModeMutex>> = ThreadModeMutex::new(RefCell::new(None)); + +pub(crate) struct Stack { + iface: Interface, + pub sockets: SocketSet, + link_up: bool, + next_local_port: u16, + configurator: &'static mut dyn Configurator, + waker: WakerRegistration, +} + +impl Stack { + pub(crate) fn with(f: impl FnOnce(&mut Stack) -> R) -> R { + let mut stack = STACK.borrow().borrow_mut(); + let stack = stack.as_mut().unwrap(); + f(stack) + } + + pub fn get_local_port(&mut self) -> u16 { + let res = self.next_local_port; + self.next_local_port = if res >= LOCAL_PORT_MAX { + LOCAL_PORT_MIN + } else { + res + 1 + }; + res + } + + pub(crate) fn wake(&mut self) { + self.waker.wake() + } + + fn poll_configurator(&mut self, timestamp: SmolInstant) { + if let Some(config) = self + .configurator + .poll(&mut self.iface, &mut self.sockets, timestamp) + { + let medium = self.iface.device().capabilities().medium; + + let (addr, gateway) = match config { + Config::Up(config) => (config.address.into(), Some(config.gateway)), + Config::Down => (IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32), None), + }; + + self.iface.update_ip_addrs(|addrs| { + let curr_addr = &mut addrs[0]; + if *curr_addr != addr { + info!("IPv4 address: {:?} -> {:?}", *curr_addr, addr); + *curr_addr = addr; + } + }); + + if medium == Medium::Ethernet { + self.iface.routes_mut().update(|r| { + let cidr = IpCidr::new(IpAddress::v4(0, 0, 0, 0), 0); + let curr_gateway = r.get(&cidr).map(|r| r.via_router); + + if curr_gateway != gateway.map(|a| a.into()) { + info!("IPv4 gateway: {:?} -> {:?}", curr_gateway, gateway); + if let Some(gateway) = gateway { + r.insert(cidr, Route::new_ipv4_gateway(gateway)).unwrap(); + } else { + r.remove(&cidr); + } + } + }); + } + } + } + + fn poll(&mut self, cx: &mut Context<'_>) { + self.iface.device_mut().device.register_waker(cx.waker()); + self.waker.register(cx.waker()); + + let timestamp = instant_to_smoltcp(Instant::now()); + if let Err(e) = self.iface.poll(&mut self.sockets, timestamp) { + // If poll() returns error, it may not be done yet, so poll again later. + cx.waker().wake_by_ref(); + return; + } + + // Update link up + let old_link_up = self.link_up; + self.link_up = self.iface.device_mut().device.link_state() == LinkState::Up; + + // Print when changed + if old_link_up != self.link_up { + if self.link_up { + info!("Link up!"); + } else { + info!("Link down!"); + } + } + + if old_link_up || self.link_up { + self.poll_configurator(timestamp) + } + + if let Some(poll_at) = self.iface.poll_at(&mut self.sockets, timestamp) { + let t = Timer::at(instant_from_smoltcp(poll_at)); + pin_mut!(t); + if t.poll(cx).is_ready() { + cx.waker().wake_by_ref(); + } + } + } +} + +/// Initialize embassy_net. +/// This function must be called from thread mode. +pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Configurator) { + let res = STACK_RESOURCES.put(StackResources { + addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32)], + neighbor_cache: [None; NEIGHBOR_CACHE_LEN], + sockets: [None; SOCKETS_LEN], + routes: [None; 1], + }); + + let ethernet_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]); + + let medium = device.capabilities().medium; + + let mut b = InterfaceBuilder::new(DeviceAdapter::new(device)); + b = b.ip_addrs(&mut res.addresses[..]); + + if medium == Medium::Ethernet { + b = b.ethernet_addr(ethernet_addr); + b = b.neighbor_cache(NeighborCache::new(&mut res.neighbor_cache[..])); + b = b.routes(Routes::new(&mut res.routes[..])); + } + + let iface = b.finalize(); + + let sockets = SocketSet::new(&mut res.sockets[..]); + + let local_port = loop { + let mut res = [0u8; 2]; + embassy::rand::rand(&mut res); + let port = u16::from_le_bytes(res); + if port >= LOCAL_PORT_MIN && port <= LOCAL_PORT_MAX { + break port; + } + }; + + let stack = Stack { + iface, + sockets, + link_up: false, + configurator, + next_local_port: local_port, + waker: WakerRegistration::new(), + }; + + *STACK.borrow().borrow_mut() = Some(stack); +} + +pub fn is_init() -> bool { + STACK.borrow().borrow().is_some() +} + +pub async fn run() { + futures::future::poll_fn(|cx| { + Stack::with(|stack| stack.poll(cx)); + Poll::<()>::Pending + }) + .await +} + +fn instant_to_smoltcp(instant: Instant) -> SmolInstant { + SmolInstant::from_millis(instant.as_millis() as i64) +} + +fn instant_from_smoltcp(instant: SmolInstant) -> Instant { + Instant::from_millis(instant.total_millis() as u64) +} -- cgit From a7d1d02be022b6dd1e5170780b509057f150ca9d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 3 Feb 2021 05:25:25 +0100 Subject: Remove use of feature(const_in_array_repeat_expressions) --- embassy-net/src/stack.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index c353f1bb1..d1dcb3bc9 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -146,10 +146,11 @@ impl Stack { /// Initialize embassy_net. /// This function must be called from thread mode. pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Configurator) { + const NONE_SOCKET: Option> = None; let res = STACK_RESOURCES.put(StackResources { addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32)], neighbor_cache: [None; NEIGHBOR_CACHE_LEN], - sockets: [None; SOCKETS_LEN], + sockets: [NONE_SOCKET; SOCKETS_LEN], routes: [None; 1], }); -- cgit From f100383b3c094830fee4e54956795388bd5edec1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 24 Feb 2021 22:31:07 +0100 Subject: Make ethernet address configurable from the Device --- embassy-net/src/stack.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index d1dcb3bc9..8f63db971 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -154,15 +154,18 @@ pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Conf routes: [None; 1], }); - let ethernet_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]); - let medium = device.capabilities().medium; + let ethernet_addr = if medium == Medium::Ethernet { + device.ethernet_address() + } else { + [0, 0, 0, 0, 0, 0] + }; let mut b = InterfaceBuilder::new(DeviceAdapter::new(device)); b = b.ip_addrs(&mut res.addresses[..]); if medium == Medium::Ethernet { - b = b.ethernet_addr(ethernet_addr); + b = b.ethernet_addr(EthernetAddress(ethernet_addr)); b = b.neighbor_cache(NeighborCache::new(&mut res.neighbor_cache[..])); b = b.routes(Routes::new(&mut res.routes[..])); } -- cgit From 9bee576fd241f019c363919b0c29551c6b8ee4b2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 2 Mar 2021 21:20:00 +0100 Subject: Update embassy --- embassy-net/src/stack.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index 8f63db971..f8a945a54 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -1,7 +1,7 @@ +use core::cell::RefCell; use core::future::Future; use core::task::Context; use core::task::Poll; -use core::{cell::RefCell, future}; use embassy::time::{Instant, Timer}; use embassy::util::ThreadModeMutex; use embassy::util::{Forever, WakerRegistration}; @@ -110,7 +110,7 @@ impl Stack { self.waker.register(cx.waker()); let timestamp = instant_to_smoltcp(Instant::now()); - if let Err(e) = self.iface.poll(&mut self.sockets, timestamp) { + if let Err(_) = self.iface.poll(&mut self.sockets, timestamp) { // If poll() returns error, it may not be done yet, so poll again later. cx.waker().wake_by_ref(); return; @@ -174,6 +174,9 @@ pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Conf let sockets = SocketSet::new(&mut res.sockets[..]); + let local_port = LOCAL_PORT_MIN; + + /* let local_port = loop { let mut res = [0u8; 2]; embassy::rand::rand(&mut res); @@ -182,6 +185,7 @@ pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Conf break port; } }; + */ let stack = Stack { iface, -- cgit From 9c5a8b945a743e75d586fdc2ef857d7c2a038e7d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 7 Apr 2021 19:06:45 +0200 Subject: Update to latest embassy, atomic-pool, smoltcp --- embassy-net/src/stack.rs | 77 ++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index f8a945a54..dc8043e67 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -11,14 +11,12 @@ use smoltcp::phy::Device as _; use smoltcp::phy::Medium; use smoltcp::socket::SocketSetItem; use smoltcp::time::Instant as SmolInstant; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; -use crate::device::{Device, DeviceAdapter}; +use crate::config::Configurator; +use crate::config::Event; +use crate::device::{Device, DeviceAdapter, LinkState}; use crate::fmt::*; -use crate::{ - config::{Config, Configurator}, - device::LinkState, -}; use crate::{Interface, SocketSet}; const ADDRESSES_LEN: usize = 1; @@ -68,39 +66,41 @@ impl Stack { } fn poll_configurator(&mut self, timestamp: SmolInstant) { - if let Some(config) = self + let medium = self.iface.device().capabilities().medium; + + match self .configurator .poll(&mut self.iface, &mut self.sockets, timestamp) { - let medium = self.iface.device().capabilities().medium; - - let (addr, gateway) = match config { - Config::Up(config) => (config.address.into(), Some(config.gateway)), - Config::Down => (IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32), None), - }; - - self.iface.update_ip_addrs(|addrs| { - let curr_addr = &mut addrs[0]; - if *curr_addr != addr { - info!("IPv4 address: {:?} -> {:?}", *curr_addr, addr); - *curr_addr = addr; - } - }); - - if medium == Medium::Ethernet { - self.iface.routes_mut().update(|r| { - let cidr = IpCidr::new(IpAddress::v4(0, 0, 0, 0), 0); - let curr_gateway = r.get(&cidr).map(|r| r.via_router); - - if curr_gateway != gateway.map(|a| a.into()) { - info!("IPv4 gateway: {:?} -> {:?}", curr_gateway, gateway); - if let Some(gateway) = gateway { - r.insert(cidr, Route::new_ipv4_gateway(gateway)).unwrap(); - } else { - r.remove(&cidr); - } + Event::NoChange => {} + Event::Configured(config) => { + debug!("Acquired IP configuration:"); + + debug!(" IP address: {}", config.address); + set_ipv4_addr(&mut self.iface, config.address); + + if medium == Medium::Ethernet { + if let Some(gateway) = config.gateway { + debug!(" Default gateway: {}", gateway); + self.iface + .routes_mut() + .add_default_ipv4_route(gateway) + .unwrap(); + } else { + debug!(" Default gateway: None"); + self.iface.routes_mut().remove_default_ipv4_route(); } - }); + } + for (i, s) in config.dns_servers.iter().enumerate() { + debug!(" DNS server {}: {}", i, s); + } + } + Event::Deconfigured => { + debug!("Lost IP configuration"); + set_ipv4_addr(&mut self.iface, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0)); + if medium == Medium::Ethernet { + self.iface.routes_mut().remove_default_ipv4_route(); + } } } } @@ -143,6 +143,13 @@ impl Stack { } } +fn set_ipv4_addr(iface: &mut Interface, cidr: Ipv4Cidr) { + iface.update_ip_addrs(|addrs| { + let dest = addrs.iter_mut().next().unwrap(); + *dest = IpCidr::Ipv4(cidr); + }); +} + /// Initialize embassy_net. /// This function must be called from thread mode. pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Configurator) { -- cgit From 54d6b6ec48145ecc33a35674f9b546b9abb01759 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Apr 2021 15:35:54 +0200 Subject: Correctly randomize source port --- embassy-net/src/stack.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index dc8043e67..9b0dd54d4 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -181,18 +181,14 @@ pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Conf let sockets = SocketSet::new(&mut res.sockets[..]); - let local_port = LOCAL_PORT_MIN; - - /* let local_port = loop { let mut res = [0u8; 2]; - embassy::rand::rand(&mut res); + rand(&mut res); let port = u16::from_le_bytes(res); if port >= LOCAL_PORT_MIN && port <= LOCAL_PORT_MAX { break port; } }; - */ let stack = Stack { iface, @@ -225,3 +221,11 @@ fn instant_to_smoltcp(instant: Instant) -> SmolInstant { fn instant_from_smoltcp(instant: SmolInstant) -> Instant { Instant::from_millis(instant.total_millis() as u64) } + +extern "Rust" { + fn _embassy_rand(buf: &mut [u8]); +} + +fn rand(buf: &mut [u8]) { + unsafe { _embassy_rand(buf) } +} -- cgit From 4f528d8fae0c57fad5c5a57f5a61fd0fc4435044 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Apr 2021 21:00:23 +0200 Subject: Add medium-ip, medium-ethernet Cargo features --- embassy-net/src/stack.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index 9b0dd54d4..83cd71707 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -6,12 +6,16 @@ use embassy::time::{Instant, Timer}; use embassy::util::ThreadModeMutex; use embassy::util::{Forever, WakerRegistration}; use futures::pin_mut; -use smoltcp::iface::{InterfaceBuilder, Neighbor, NeighborCache, Route, Routes}; +use smoltcp::iface::InterfaceBuilder; +#[cfg(feature = "medium-ethernet")] +use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes}; use smoltcp::phy::Device as _; use smoltcp::phy::Medium; use smoltcp::socket::SocketSetItem; use smoltcp::time::Instant as SmolInstant; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; +#[cfg(feature = "medium-ethernet")] +use smoltcp::wire::EthernetAddress; +use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; use crate::config::Configurator; use crate::config::Event; @@ -27,9 +31,12 @@ const LOCAL_PORT_MAX: u16 = 65535; struct StackResources { addresses: [IpCidr; ADDRESSES_LEN], - neighbor_cache: [Option<(IpAddress, Neighbor)>; NEIGHBOR_CACHE_LEN], sockets: [Option>; SOCKETS_LEN], + + #[cfg(feature = "medium-ethernet")] routes: [Option<(IpCidr, Route)>; 1], + #[cfg(feature = "medium-ethernet")] + neighbor_cache: [Option<(IpAddress, Neighbor)>; NEIGHBOR_CACHE_LEN], } static STACK_RESOURCES: Forever = Forever::new(); @@ -79,6 +86,7 @@ impl Stack { debug!(" IP address: {}", config.address); set_ipv4_addr(&mut self.iface, config.address); + #[cfg(feature = "medium-ethernet")] if medium == Medium::Ethernet { if let Some(gateway) = config.gateway { debug!(" Default gateway: {}", gateway); @@ -98,6 +106,7 @@ impl Stack { Event::Deconfigured => { debug!("Lost IP configuration"); set_ipv4_addr(&mut self.iface, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0)); + #[cfg(feature = "medium-ethernet")] if medium == Medium::Ethernet { self.iface.routes_mut().remove_default_ipv4_route(); } @@ -156,12 +165,17 @@ pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Conf const NONE_SOCKET: Option> = None; let res = STACK_RESOURCES.put(StackResources { addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32)], - neighbor_cache: [None; NEIGHBOR_CACHE_LEN], sockets: [NONE_SOCKET; SOCKETS_LEN], + + #[cfg(feature = "medium-ethernet")] routes: [None; 1], + #[cfg(feature = "medium-ethernet")] + neighbor_cache: [None; NEIGHBOR_CACHE_LEN], }); let medium = device.capabilities().medium; + + #[cfg(feature = "medium-ethernet")] let ethernet_addr = if medium == Medium::Ethernet { device.ethernet_address() } else { @@ -171,6 +185,7 @@ pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Conf let mut b = InterfaceBuilder::new(DeviceAdapter::new(device)); b = b.ip_addrs(&mut res.addresses[..]); + #[cfg(feature = "medium-ethernet")] if medium == Medium::Ethernet { b = b.ethernet_addr(EthernetAddress(ethernet_addr)); b = b.neighbor_cache(NeighborCache::new(&mut res.neighbor_cache[..])); -- cgit From 4eecb3cfa982abfd4fe97108f14d15236addb9b2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Apr 2021 17:14:23 +0200 Subject: add is_link_up, is_config_up --- embassy-net/src/stack.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'embassy-net/src/stack.rs') diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index 83cd71707..e436beb1e 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs @@ -46,6 +46,7 @@ pub(crate) struct Stack { iface: Interface, pub sockets: SocketSet, link_up: bool, + config_up: bool, next_local_port: u16, configurator: &'static mut dyn Configurator, waker: WakerRegistration, @@ -102,6 +103,8 @@ impl Stack { for (i, s) in config.dns_servers.iter().enumerate() { debug!(" DNS server {}: {}", i, s); } + + self.config_up = true; } Event::Deconfigured => { debug!("Lost IP configuration"); @@ -110,6 +113,7 @@ impl Stack { if medium == Medium::Ethernet { self.iface.routes_mut().remove_default_ipv4_route(); } + self.config_up = false; } } } @@ -209,6 +213,7 @@ pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Conf iface, sockets, link_up: false, + config_up: false, configurator, next_local_port: local_port, waker: WakerRegistration::new(), @@ -221,6 +226,14 @@ pub fn is_init() -> bool { STACK.borrow().borrow().is_some() } +pub fn is_link_up() -> bool { + STACK.borrow().borrow().as_ref().unwrap().link_up +} + +pub fn is_config_up() -> bool { + STACK.borrow().borrow().as_ref().unwrap().config_up +} + pub async fn run() { futures::future::poll_fn(|cx| { Stack::with(|stack| stack.poll(cx)); -- cgit