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/config/dhcp.rs | 80 +++++++++++++ embassy-net/src/config/mod.rs | 34 ++++++ embassy-net/src/config/statik.rs | 26 +++++ embassy-net/src/device.rs | 103 ++++++++++++++++ embassy-net/src/fmt.rs | 118 +++++++++++++++++++ embassy-net/src/lib.rs | 31 +++++ embassy-net/src/packet_pool.rs | 88 ++++++++++++++ embassy-net/src/pool.rs | 245 +++++++++++++++++++++++++++++++++++++++ embassy-net/src/stack.rs | 212 +++++++++++++++++++++++++++++++++ embassy-net/src/tcp_socket.rs | 178 ++++++++++++++++++++++++++++ 10 files changed, 1115 insertions(+) create mode 100644 embassy-net/src/config/dhcp.rs create mode 100644 embassy-net/src/config/mod.rs create mode 100644 embassy-net/src/config/statik.rs create mode 100644 embassy-net/src/device.rs create mode 100644 embassy-net/src/fmt.rs create mode 100644 embassy-net/src/lib.rs create mode 100644 embassy-net/src/packet_pool.rs create mode 100644 embassy-net/src/pool.rs create mode 100644 embassy-net/src/stack.rs create mode 100644 embassy-net/src/tcp_socket.rs (limited to 'embassy-net/src') diff --git a/embassy-net/src/config/dhcp.rs b/embassy-net/src/config/dhcp.rs new file mode 100644 index 000000000..f5d598bdf --- /dev/null +++ b/embassy-net/src/config/dhcp.rs @@ -0,0 +1,80 @@ +use embassy::util::Forever; +use heapless::consts::*; +use heapless::Vec; +use smoltcp::dhcp::Dhcpv4Client; +use smoltcp::socket::{RawPacketMetadata, RawSocketBuffer}; +use smoltcp::time::Instant; +use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; + +use super::*; +use crate::{device::LinkState, fmt::*}; +use crate::{Interface, SocketSet}; + +pub struct DhcpResources { + rx_buffer: [u8; 900], + tx_buffer: [u8; 600], + rx_meta: [RawPacketMetadata; 1], + tx_meta: [RawPacketMetadata; 1], +} + +pub struct DhcpConfigurator { + client: Option, +} + +impl DhcpConfigurator { + pub fn new() -> Self { + Self { client: None } + } +} + +static DHCP_RESOURCES: Forever = Forever::new(); + +impl Configurator for DhcpConfigurator { + fn poll( + &mut self, + iface: &mut Interface, + sockets: &mut SocketSet, + timestamp: Instant, + ) -> Option { + if self.client.is_none() { + let res = DHCP_RESOURCES.put(DhcpResources { + rx_buffer: [0; 900], + tx_buffer: [0; 600], + rx_meta: [RawPacketMetadata::EMPTY; 1], + tx_meta: [RawPacketMetadata::EMPTY; 1], + }); + let rx_buffer = RawSocketBuffer::new(&mut res.rx_meta[..], &mut res.rx_buffer[..]); + let tx_buffer = RawSocketBuffer::new(&mut res.tx_meta[..], &mut res.tx_buffer[..]); + let dhcp = Dhcpv4Client::new(sockets, rx_buffer, tx_buffer, timestamp); + info!("created dhcp"); + self.client = Some(dhcp) + } + + let client = self.client.as_mut().unwrap(); + + let link_up = iface.device_mut().device.link_state() == LinkState::Up; + if !link_up { + client.reset(timestamp); + return Some(Config::Down); + } + + let config = client.poll(iface, sockets, timestamp).unwrap_or(None)?; + + if config.address.is_none() { + return Some(Config::Down); + } + + let mut dns_servers = Vec::new(); + for s in &config.dns_servers { + if let Some(addr) = s { + dns_servers.push(addr.clone()).unwrap(); + } + } + + return Some(Config::Up(UpConfig { + address: config.address.unwrap(), + gateway: config.router.unwrap_or(Ipv4Address::UNSPECIFIED), + dns_servers, + })); + } +} diff --git a/embassy-net/src/config/mod.rs b/embassy-net/src/config/mod.rs new file mode 100644 index 000000000..596374f9e --- /dev/null +++ b/embassy-net/src/config/mod.rs @@ -0,0 +1,34 @@ +use heapless::consts::*; +use heapless::Vec; +use smoltcp::time::Instant; +use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; + +use crate::fmt::*; +use crate::{Interface, SocketSet}; + +mod dhcp; +mod statik; +pub use dhcp::DhcpConfigurator; +pub use statik::StaticConfigurator; + +#[derive(Debug, Clone)] +pub enum Config { + Down, + Up(UpConfig), +} + +#[derive(Debug, Clone)] +pub struct UpConfig { + pub address: Ipv4Cidr, + pub gateway: Ipv4Address, + pub dns_servers: Vec, +} + +pub trait Configurator { + fn poll( + &mut self, + iface: &mut Interface, + sockets: &mut SocketSet, + timestamp: Instant, + ) -> Option; +} diff --git a/embassy-net/src/config/statik.rs b/embassy-net/src/config/statik.rs new file mode 100644 index 000000000..52196f48a --- /dev/null +++ b/embassy-net/src/config/statik.rs @@ -0,0 +1,26 @@ +use smoltcp::time::Instant; + +use super::*; +use crate::fmt::*; +use crate::{Interface, SocketSet}; + +pub struct StaticConfigurator { + config: UpConfig, +} + +impl StaticConfigurator { + pub fn new(config: UpConfig) -> Self { + Self { config } + } +} + +impl Configurator for StaticConfigurator { + fn poll( + &mut self, + _iface: &mut Interface, + _sockets: &mut SocketSet, + _timestamp: Instant, + ) -> Option { + Some(Config::Up(self.config.clone())) + } +} diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs new file mode 100644 index 000000000..95a62e792 --- /dev/null +++ b/embassy-net/src/device.rs @@ -0,0 +1,103 @@ +use core::task::{Poll, Waker}; +use smoltcp::phy::Device as SmolDevice; +use smoltcp::phy::DeviceCapabilities; +use smoltcp::time::Instant as SmolInstant; +use smoltcp::Result; + +use crate::fmt::*; +use crate::{Packet, PacketBox, PacketBuf}; + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum LinkState { + Down, + Up, +} + +pub trait Device { + fn is_transmit_ready(&mut self) -> bool; + fn transmit(&mut self, pkt: PacketBuf); + fn receive(&mut self) -> Option; + + fn register_waker(&mut self, waker: &Waker); + fn capabilities(&mut self) -> DeviceCapabilities; + fn link_state(&mut self) -> LinkState; +} + +pub struct DeviceAdapter { + pub device: &'static mut dyn Device, + caps: DeviceCapabilities, +} + +impl DeviceAdapter { + pub(crate) fn new(device: &'static mut dyn Device) -> Self { + Self { + caps: device.capabilities(), + device, + } + } +} + +impl<'a> SmolDevice<'a> for DeviceAdapter { + type RxToken = RxToken; + type TxToken = TxToken<'a>; + + fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + let rx_pkt = self.device.receive()?; + let tx_pkt = PacketBox::new(Packet::new()).unwrap(); // TODO: not sure about unwrap + let rx_token = RxToken { pkt: rx_pkt }; + let tx_token = TxToken { + device: self.device, + pkt: tx_pkt, + }; + + Some((rx_token, tx_token)) + } + + /// Construct a transmit token. + fn transmit(&'a mut self) -> Option { + if !self.device.is_transmit_ready() { + return None; + } + + let tx_pkt = PacketBox::new(Packet::new())?; + Some(TxToken { + device: self.device, + pkt: tx_pkt, + }) + } + + /// Get a description of device capabilities. + fn capabilities(&self) -> DeviceCapabilities { + self.caps.clone() + } +} + +pub struct RxToken { + pkt: PacketBuf, +} + +impl smoltcp::phy::RxToken for RxToken { + fn consume(mut self, _timestamp: SmolInstant, f: F) -> Result + where + F: FnOnce(&mut [u8]) -> Result, + { + f(&mut self.pkt) + } +} + +pub struct TxToken<'a> { + device: &'a mut dyn Device, + pkt: PacketBox, +} + +impl<'a> smoltcp::phy::TxToken for TxToken<'a> { + fn consume(mut self, _timestamp: SmolInstant, len: usize, f: F) -> Result + where + F: FnOnce(&mut [u8]) -> Result, + { + let mut buf = self.pkt.slice(0..len); + let r = f(&mut buf)?; + self.device.transmit(buf); + Ok(r) + } +} diff --git a/embassy-net/src/fmt.rs b/embassy-net/src/fmt.rs new file mode 100644 index 000000000..4da69766c --- /dev/null +++ b/embassy-net/src/fmt.rs @@ -0,0 +1,118 @@ +#![macro_use] + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +pub use fmt::*; + +#[cfg(feature = "defmt")] +mod fmt { + pub use defmt::{ + assert, assert_eq, assert_ne, debug, debug_assert, debug_assert_eq, debug_assert_ne, error, + info, panic, todo, trace, unreachable, unwrap, warn, + }; +} + +#[cfg(feature = "log")] +mod fmt { + pub use core::{ + assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo, + unreachable, + }; + pub use log::{debug, error, info, trace, warn}; +} + +#[cfg(not(any(feature = "defmt", feature = "log")))] +mod fmt { + #![macro_use] + + pub use core::{ + assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo, + unreachable, + }; + + #[macro_export] + macro_rules! trace { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! debug { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! info { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! warn { + ($($msg:expr),+ $(,)?) => { + () + }; + } + + #[macro_export] + macro_rules! error { + ($($msg:expr),+ $(,)?) => { + () + }; + } +} + +#[cfg(not(feature = "defmt"))] +#[macro_export] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs new file mode 100644 index 000000000..a2a320adf --- /dev/null +++ b/embassy-net/src/lib.rs @@ -0,0 +1,31 @@ +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(const_fn)] +#![feature(const_in_array_repeat_expressions)] +#![feature(const_generics)] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + +mod pool; // TODO extract to embassy, or to own crate + +mod config; +mod device; +mod packet_pool; +mod stack; +mod tcp_socket; + +pub use config::{Config, Configurator, DhcpConfigurator, StaticConfigurator, UpConfig}; +pub use device::{Device, LinkState}; +pub use packet_pool::{Packet, PacketBox, PacketBuf}; +pub use stack::{init, is_init, run}; +pub use tcp_socket::TcpSocket; + +// smoltcp reexports +pub use smoltcp::phy::{DeviceCapabilities, Medium}; +pub use smoltcp::time::Duration as SmolDuration; +pub use smoltcp::time::Instant as SmolInstant; +pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; +pub type Interface = smoltcp::iface::Interface<'static, device::DeviceAdapter>; +pub type SocketSet = smoltcp::socket::SocketSet<'static>; diff --git a/embassy-net/src/packet_pool.rs b/embassy-net/src/packet_pool.rs new file mode 100644 index 000000000..246356431 --- /dev/null +++ b/embassy-net/src/packet_pool.rs @@ -0,0 +1,88 @@ +use as_slice::{AsMutSlice, AsSlice}; +use core::ops::{Deref, DerefMut, Range}; + +use super::pool::{BitPool, Box, StaticPool}; + +pub const MTU: usize = 1514; +pub const PACKET_POOL_SIZE: usize = 4; + +pool!(pub PacketPool: [Packet; PACKET_POOL_SIZE]); +pub type PacketBox = Box; + +pub struct Packet(pub [u8; MTU]); + +impl Packet { + pub const fn new() -> Self { + Self([0; MTU]) + } +} + +impl Box { + pub fn slice(self, range: Range) -> PacketBuf { + PacketBuf { + packet: self, + range, + } + } +} + +impl AsSlice for Packet { + type Element = u8; + + fn as_slice(&self) -> &[Self::Element] { + &self.deref()[..] + } +} + +impl AsMutSlice for Packet { + fn as_mut_slice(&mut self) -> &mut [Self::Element] { + &mut self.deref_mut()[..] + } +} + +impl Deref for Packet { + type Target = [u8; MTU]; + + fn deref(&self) -> &[u8; MTU] { + &self.0 + } +} + +impl DerefMut for Packet { + fn deref_mut(&mut self) -> &mut [u8; MTU] { + &mut self.0 + } +} + +pub struct PacketBuf { + packet: PacketBox, + range: Range, +} + +impl AsSlice for PacketBuf { + type Element = u8; + + fn as_slice(&self) -> &[Self::Element] { + &self.packet[self.range.clone()] + } +} + +impl AsMutSlice for PacketBuf { + fn as_mut_slice(&mut self) -> &mut [Self::Element] { + &mut self.packet[self.range.clone()] + } +} + +impl Deref for PacketBuf { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + &self.packet[self.range.clone()] + } +} + +impl DerefMut for PacketBuf { + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.packet[self.range.clone()] + } +} diff --git a/embassy-net/src/pool.rs b/embassy-net/src/pool.rs new file mode 100644 index 000000000..3ab36e4cc --- /dev/null +++ b/embassy-net/src/pool.rs @@ -0,0 +1,245 @@ +#![macro_use] + +use as_slice::{AsMutSlice, AsSlice}; +use core::cmp; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::{AtomicU32, Ordering}; + +use crate::fmt::{assert, *}; + +struct AtomicBitset +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + used: [AtomicU32; (N + 31) / 32], +} + +impl AtomicBitset +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + const fn new() -> Self { + const Z: AtomicU32 = AtomicU32::new(0); + Self { + used: [Z; (N + 31) / 32], + } + } + + fn alloc(&self) -> Option { + for (i, val) in self.used.iter().enumerate() { + let res = val.fetch_update(Ordering::AcqRel, Ordering::Acquire, |val| { + let n = val.trailing_ones() as usize + i * 32; + if n >= N { + None + } else { + Some(val | (1 << n)) + } + }); + if let Ok(val) = res { + let n = val.trailing_ones() as usize + i * 32; + return Some(n); + } + } + None + } + fn free(&self, i: usize) { + assert!(i < N); + self.used[i / 32].fetch_and(!(1 << ((i % 32) as u32)), Ordering::AcqRel); + } +} + +pub trait Pool { + fn alloc(&self) -> Option<*mut T>; + unsafe fn free(&self, p: *mut T); +} + +pub struct BitPool +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + used: AtomicBitset, + data: MaybeUninit<[T; N]>, +} + +impl BitPool +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + pub const fn new() -> Self { + Self { + used: AtomicBitset::new(), + data: MaybeUninit::uninit(), + } + } +} + +impl Pool for BitPool +where + [AtomicU32; (N + 31) / 32]: Sized, +{ + fn alloc(&self) -> Option<*mut T> { + let n = self.used.alloc()?; + let origin = self.data.as_ptr() as *mut T; + Some(unsafe { origin.add(n) }) + } + + /// safety: p must be a pointer obtained from self.alloc that hasn't been freed yet. + unsafe fn free(&self, p: *mut T) { + let origin = self.data.as_ptr() as *mut T; + let n = p.offset_from(origin); + assert!(n >= 0); + assert!((n as usize) < N); + self.used.free(n as usize); + } +} + +pub trait StaticPool: 'static { + type Item: 'static; + type Pool: Pool; + fn get() -> &'static Self::Pool; +} + +pub struct Box { + ptr: *mut P::Item, +} + +impl Box

{ + pub fn new(item: P::Item) -> Option { + let p = match P::get().alloc() { + Some(p) => p, + None => { + warn!("alloc failed!"); + return None; + } + }; + //trace!("allocated {:u32}", p as u32); + unsafe { p.write(item) }; + Some(Self { ptr: p }) + } +} + +impl Drop for Box

{ + fn drop(&mut self) { + unsafe { + //trace!("dropping {:u32}", self.ptr as u32); + self.ptr.drop_in_place(); + P::get().free(self.ptr); + }; + } +} + +unsafe impl Send for Box

where P::Item: Send {} + +unsafe impl Sync for Box

where P::Item: Sync {} + +unsafe impl stable_deref_trait::StableDeref for Box

{} + +impl AsSlice for Box

+where + P::Item: AsSlice, +{ + type Element = ::Element; + + fn as_slice(&self) -> &[Self::Element] { + self.deref().as_slice() + } +} + +impl AsMutSlice for Box

+where + P::Item: AsMutSlice, +{ + fn as_mut_slice(&mut self) -> &mut [Self::Element] { + self.deref_mut().as_mut_slice() + } +} + +impl Deref for Box

{ + type Target = P::Item; + + fn deref(&self) -> &P::Item { + unsafe { &*self.ptr } + } +} + +impl DerefMut for Box

{ + fn deref_mut(&mut self) -> &mut P::Item { + unsafe { &mut *self.ptr } + } +} + +impl fmt::Debug for Box

+where + P::Item: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(self, f) + } +} + +impl fmt::Display for Box

+where + P::Item: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(self, f) + } +} + +impl PartialEq for Box

+where + P::Item: PartialEq, +{ + fn eq(&self, rhs: &Box

) -> bool { + ::eq(self, rhs) + } +} + +impl Eq for Box

where P::Item: Eq {} + +impl PartialOrd for Box

+where + P::Item: PartialOrd, +{ + fn partial_cmp(&self, rhs: &Box

) -> Option { + ::partial_cmp(self, rhs) + } +} + +impl Ord for Box

+where + P::Item: Ord, +{ + fn cmp(&self, rhs: &Box

) -> cmp::Ordering { + ::cmp(self, rhs) + } +} + +impl Hash for Box

+where + P::Item: Hash, +{ + fn hash(&self, state: &mut H) + where + H: Hasher, + { + ::hash(self, state) + } +} + +macro_rules! pool { + ($vis:vis $name:ident: [$ty:ty; $size:expr]) => { + $vis struct $name; + impl StaticPool for $name { + type Item = $ty; + type Pool = BitPool<$ty, $size>; + fn get() -> &'static Self::Pool { + static POOL: BitPool<$ty, $size> = BitPool::new(); + &POOL + } + } + }; +} 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) +} diff --git a/embassy-net/src/tcp_socket.rs b/embassy-net/src/tcp_socket.rs new file mode 100644 index 000000000..7f4eb014c --- /dev/null +++ b/embassy-net/src/tcp_socket.rs @@ -0,0 +1,178 @@ +use core::marker::PhantomData; +use core::mem; +use core::pin::Pin; +use core::task::{Context, Poll}; +use embassy::io; +use embassy::io::{AsyncBufRead, AsyncWrite}; +use smoltcp::socket::SocketHandle; +use smoltcp::socket::TcpSocket as SyncTcpSocket; +use smoltcp::socket::{TcpSocketBuffer, TcpState}; +use smoltcp::time::Duration; +use smoltcp::wire::IpEndpoint; +use smoltcp::{Error, Result}; + +use super::stack::Stack; +use crate::fmt::*; + +pub struct TcpSocket<'a> { + handle: SocketHandle, + ghost: PhantomData<&'a mut [u8]>, +} + +impl<'a> Unpin for TcpSocket<'a> {} + +impl<'a> TcpSocket<'a> { + pub fn new(rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { + let handle = Stack::with(|stack| { + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + stack.sockets.add(SyncTcpSocket::new( + TcpSocketBuffer::new(rx_buffer), + TcpSocketBuffer::new(tx_buffer), + )) + }); + + Self { + handle, + ghost: PhantomData, + } + } + + pub async fn connect(&mut self, remote_endpoint: T) -> Result<()> + where + T: Into, + { + let local_port = Stack::with(|stack| stack.get_local_port()); + self.with(|s| s.connect(remote_endpoint, local_port))?; + + futures::future::poll_fn(|cx| { + self.with(|s| match s.state() { + TcpState::Closed | TcpState::TimeWait => Poll::Ready(Err(Error::Unaddressable)), + TcpState::Listen => Poll::Ready(Err(Error::Illegal)), + TcpState::SynSent | TcpState::SynReceived => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + _ => Poll::Ready(Ok(())), + }) + }) + .await + } + + pub fn set_timeout(&mut self, duration: Option) { + self.with(|s| s.set_timeout(duration)) + } + + pub fn set_keep_alive(&mut self, interval: Option) { + self.with(|s| s.set_keep_alive(interval)) + } + + pub fn set_hop_limit(&mut self, hop_limit: Option) { + self.with(|s| s.set_hop_limit(hop_limit)) + } + + pub fn local_endpoint(&self) -> IpEndpoint { + self.with(|s| s.local_endpoint()) + } + + pub fn remote_endpoint(&self) -> IpEndpoint { + self.with(|s| s.remote_endpoint()) + } + + pub fn state(&self) -> TcpState { + self.with(|s| s.state()) + } + + pub fn close(&mut self) { + self.with(|s| s.close()) + } + + pub fn abort(&mut self) { + self.with(|s| s.abort()) + } + + pub fn may_send(&self) -> bool { + self.with(|s| s.may_send()) + } + + pub fn may_recv(&self) -> bool { + self.with(|s| s.may_recv()) + } + + fn with(&self, f: impl FnOnce(&mut SyncTcpSocket) -> R) -> R { + Stack::with(|stack| { + let res = { + let mut s = stack.sockets.get::(self.handle); + f(&mut *s) + }; + stack.wake(); + res + }) + } +} + +fn to_ioerr(e: Error) -> io::Error { + warn!("smoltcp err: {:?}", e); + // todo + io::Error::Other +} + +impl<'a> Drop for TcpSocket<'a> { + fn drop(&mut self) { + Stack::with(|stack| { + stack.sockets.remove(self.handle); + }) + } +} + +impl<'a> AsyncBufRead for TcpSocket<'a> { + fn poll_fill_buf<'z>( + self: Pin<&'z mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.with(|socket| match socket.peek(1 << 30) { + // No data ready + Ok(buf) if buf.len() == 0 => { + socket.register_recv_waker(cx.waker()); + Poll::Pending + } + // Data ready! + Ok(buf) => { + // Safety: + // - User can't touch the inner TcpSocket directly at all. + // - The socket itself won't touch these bytes until consume() is called, which + // requires the user to release this borrow. + let buf: &'z [u8] = unsafe { core::mem::transmute(&*buf) }; + Poll::Ready(Ok(buf)) + } + // EOF + Err(Error::Finished) => Poll::Ready(Ok(&[][..])), + // Error + Err(e) => Poll::Ready(Err(to_ioerr(e))), + }) + } + + fn consume(self: Pin<&mut Self>, amt: usize) { + self.with(|s| s.recv(|_| (amt, ()))).unwrap() + } +} + +impl<'a> AsyncWrite for TcpSocket<'a> { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + self.with(|s| match s.send_slice(buf) { + // Not ready to send (no space in the tx buffer) + Ok(0) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + // Some data sent + Ok(n) => Poll::Ready(Ok(n)), + // Error + Err(e) => Poll::Ready(Err(to_ioerr(e))), + }) + } +} -- cgit From 10cd5bddc91280009d6951e34a67b1a01c7e2166 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 3 Feb 2021 05:15:13 +0100 Subject: Add CI --- embassy-net/src/tcp_socket.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/tcp_socket.rs b/embassy-net/src/tcp_socket.rs index 7f4eb014c..eab8189de 100644 --- a/embassy-net/src/tcp_socket.rs +++ b/embassy-net/src/tcp_socket.rs @@ -112,7 +112,6 @@ impl<'a> TcpSocket<'a> { } fn to_ioerr(e: Error) -> io::Error { - warn!("smoltcp err: {:?}", e); // todo io::Error::Other } -- 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/lib.rs | 1 - embassy-net/src/stack.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index a2a320adf..fe1d529d8 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,6 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] #![feature(const_fn)] -#![feature(const_in_array_repeat_expressions)] #![feature(const_generics)] #![feature(const_evaluatable_checked)] #![allow(incomplete_features)] 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 7d3878466cfecde17f5e707d65503435394f7ae5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Feb 2021 01:48:21 +0100 Subject: reexport smoltcp error/result --- embassy-net/src/device.rs | 2 +- embassy-net/src/lib.rs | 1 + embassy-net/src/tcp_socket.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 95a62e792..ea23635c7 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -2,10 +2,10 @@ use core::task::{Poll, Waker}; use smoltcp::phy::Device as SmolDevice; use smoltcp::phy::DeviceCapabilities; use smoltcp::time::Instant as SmolInstant; -use smoltcp::Result; use crate::fmt::*; use crate::{Packet, PacketBox, PacketBuf}; +use crate::Result; #[derive(PartialEq, Eq, Clone, Copy)] pub enum LinkState { diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index fe1d529d8..de2f2ea74 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -28,3 +28,4 @@ pub use smoltcp::time::Instant as SmolInstant; pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; pub type Interface = smoltcp::iface::Interface<'static, device::DeviceAdapter>; pub type SocketSet = smoltcp::socket::SocketSet<'static>; +pub use smoltcp::{Error, Result}; \ No newline at end of file diff --git a/embassy-net/src/tcp_socket.rs b/embassy-net/src/tcp_socket.rs index eab8189de..84f096525 100644 --- a/embassy-net/src/tcp_socket.rs +++ b/embassy-net/src/tcp_socket.rs @@ -9,10 +9,10 @@ use smoltcp::socket::TcpSocket as SyncTcpSocket; use smoltcp::socket::{TcpSocketBuffer, TcpState}; use smoltcp::time::Duration; use smoltcp::wire::IpEndpoint; -use smoltcp::{Error, Result}; use super::stack::Stack; use crate::fmt::*; +use crate::{Error, Result}; pub struct TcpSocket<'a> { handle: SocketHandle, -- 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/device.rs | 1 + embassy-net/src/stack.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index ea23635c7..5a266f4ef 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -21,6 +21,7 @@ pub trait Device { fn register_waker(&mut self, waker: &Waker); fn capabilities(&mut self) -> DeviceCapabilities; fn link_state(&mut self) -> LinkState; + fn ethernet_address(&mut self) -> [u8;6]; } pub struct DeviceAdapter { 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/config/dhcp.rs | 6 +++--- embassy-net/src/device.rs | 8 ++++---- embassy-net/src/stack.rs | 8 ++++++-- embassy-net/src/tcp_socket.rs | 2 +- 4 files changed, 14 insertions(+), 10 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/config/dhcp.rs b/embassy-net/src/config/dhcp.rs index f5d598bdf..0df67baf5 100644 --- a/embassy-net/src/config/dhcp.rs +++ b/embassy-net/src/config/dhcp.rs @@ -1,13 +1,13 @@ use embassy::util::Forever; -use heapless::consts::*; use heapless::Vec; use smoltcp::dhcp::Dhcpv4Client; use smoltcp::socket::{RawPacketMetadata, RawSocketBuffer}; use smoltcp::time::Instant; -use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; +use smoltcp::wire::Ipv4Address; use super::*; -use crate::{device::LinkState, fmt::*}; +use crate::device::LinkState; +use crate::fmt::*; use crate::{Interface, SocketSet}; pub struct DhcpResources { diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 5a266f4ef..32b56e5be 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -1,11 +1,11 @@ -use core::task::{Poll, Waker}; +use core::task::Waker; use smoltcp::phy::Device as SmolDevice; use smoltcp::phy::DeviceCapabilities; use smoltcp::time::Instant as SmolInstant; use crate::fmt::*; -use crate::{Packet, PacketBox, PacketBuf}; use crate::Result; +use crate::{Packet, PacketBox, PacketBuf}; #[derive(PartialEq, Eq, Clone, Copy)] pub enum LinkState { @@ -21,7 +21,7 @@ pub trait Device { fn register_waker(&mut self, waker: &Waker); fn capabilities(&mut self) -> DeviceCapabilities; fn link_state(&mut self) -> LinkState; - fn ethernet_address(&mut self) -> [u8;6]; + fn ethernet_address(&mut self) -> [u8; 6]; } pub struct DeviceAdapter { @@ -92,7 +92,7 @@ pub struct TxToken<'a> { } impl<'a> smoltcp::phy::TxToken for TxToken<'a> { - fn consume(mut self, _timestamp: SmolInstant, len: usize, f: F) -> Result + fn consume(self, _timestamp: SmolInstant, len: usize, f: F) -> Result where F: FnOnce(&mut [u8]) -> Result, { 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, diff --git a/embassy-net/src/tcp_socket.rs b/embassy-net/src/tcp_socket.rs index 84f096525..4f43bc611 100644 --- a/embassy-net/src/tcp_socket.rs +++ b/embassy-net/src/tcp_socket.rs @@ -111,7 +111,7 @@ impl<'a> TcpSocket<'a> { } } -fn to_ioerr(e: Error) -> io::Error { +fn to_ioerr(_err: Error) -> io::Error { // todo io::Error::Other } -- 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/config/dhcp.rs | 75 +++++------- embassy-net/src/config/mod.rs | 30 ++--- embassy-net/src/config/statik.rs | 19 ++- embassy-net/src/device.rs | 1 + embassy-net/src/lib.rs | 13 ++- embassy-net/src/packet_pool.rs | 10 +- embassy-net/src/pool.rs | 245 --------------------------------------- embassy-net/src/stack.rs | 77 ++++++------ 8 files changed, 115 insertions(+), 355 deletions(-) delete mode 100644 embassy-net/src/pool.rs (limited to 'embassy-net/src') diff --git a/embassy-net/src/config/dhcp.rs b/embassy-net/src/config/dhcp.rs index 0df67baf5..007c398b3 100644 --- a/embassy-net/src/config/dhcp.rs +++ b/embassy-net/src/config/dhcp.rs @@ -1,80 +1,59 @@ -use embassy::util::Forever; use heapless::Vec; -use smoltcp::dhcp::Dhcpv4Client; -use smoltcp::socket::{RawPacketMetadata, RawSocketBuffer}; +use smoltcp::socket::{Dhcpv4Event, Dhcpv4Socket, SocketHandle}; use smoltcp::time::Instant; -use smoltcp::wire::Ipv4Address; use super::*; use crate::device::LinkState; use crate::fmt::*; use crate::{Interface, SocketSet}; -pub struct DhcpResources { - rx_buffer: [u8; 900], - tx_buffer: [u8; 600], - rx_meta: [RawPacketMetadata; 1], - tx_meta: [RawPacketMetadata; 1], -} - pub struct DhcpConfigurator { - client: Option, + handle: Option, } impl DhcpConfigurator { pub fn new() -> Self { - Self { client: None } + Self { handle: None } } } -static DHCP_RESOURCES: Forever = Forever::new(); - impl Configurator for DhcpConfigurator { fn poll( &mut self, iface: &mut Interface, sockets: &mut SocketSet, - timestamp: Instant, - ) -> Option { - if self.client.is_none() { - let res = DHCP_RESOURCES.put(DhcpResources { - rx_buffer: [0; 900], - tx_buffer: [0; 600], - rx_meta: [RawPacketMetadata::EMPTY; 1], - tx_meta: [RawPacketMetadata::EMPTY; 1], - }); - let rx_buffer = RawSocketBuffer::new(&mut res.rx_meta[..], &mut res.rx_buffer[..]); - let tx_buffer = RawSocketBuffer::new(&mut res.tx_meta[..], &mut res.tx_buffer[..]); - let dhcp = Dhcpv4Client::new(sockets, rx_buffer, tx_buffer, timestamp); - info!("created dhcp"); - self.client = Some(dhcp) + _timestamp: Instant, + ) -> Event { + if self.handle.is_none() { + let handle = sockets.add(Dhcpv4Socket::new()); + self.handle = Some(handle) } - let client = self.client.as_mut().unwrap(); + let mut socket = sockets.get::(self.handle.unwrap()); let link_up = iface.device_mut().device.link_state() == LinkState::Up; if !link_up { - client.reset(timestamp); - return Some(Config::Down); + socket.reset(); + return Event::Deconfigured; } - let config = client.poll(iface, sockets, timestamp).unwrap_or(None)?; - - if config.address.is_none() { - return Some(Config::Down); - } - - let mut dns_servers = Vec::new(); - for s in &config.dns_servers { - if let Some(addr) = s { - dns_servers.push(addr.clone()).unwrap(); + match socket.poll() { + Dhcpv4Event::NoChange => Event::NoChange, + Dhcpv4Event::Deconfigured => Event::Deconfigured, + Dhcpv4Event::Configured(config) => { + let mut dns_servers = Vec::new(); + for s in &config.dns_servers { + if let Some(addr) = s { + dns_servers.push(addr.clone()).unwrap(); + } + } + + Event::Configured(Config { + address: config.address, + gateway: config.router, + dns_servers, + }) } } - - return Some(Config::Up(UpConfig { - address: config.address.unwrap(), - gateway: config.router.unwrap_or(Ipv4Address::UNSPECIFIED), - dns_servers, - })); } } diff --git a/embassy-net/src/config/mod.rs b/embassy-net/src/config/mod.rs index 596374f9e..a090aaacf 100644 --- a/embassy-net/src/config/mod.rs +++ b/embassy-net/src/config/mod.rs @@ -6,29 +6,33 @@ use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; use crate::fmt::*; use crate::{Interface, SocketSet}; -mod dhcp; mod statik; -pub use dhcp::DhcpConfigurator; pub use statik::StaticConfigurator; +#[cfg(feature = "dhcpv4")] +mod dhcp; +#[cfg(feature = "dhcpv4")] +pub use dhcp::DhcpConfigurator; + +/// Return value for the `Configurator::poll` function #[derive(Debug, Clone)] -pub enum Config { - Down, - Up(UpConfig), +pub enum Event { + /// No change has occured to the configuration. + NoChange, + /// Configuration has been lost (for example, DHCP lease has expired) + Deconfigured, + /// Configuration has been newly acquired, or modified. + Configured(Config), } #[derive(Debug, Clone)] -pub struct UpConfig { +pub struct Config { pub address: Ipv4Cidr, - pub gateway: Ipv4Address, + pub gateway: Option, pub dns_servers: Vec, } pub trait Configurator { - fn poll( - &mut self, - iface: &mut Interface, - sockets: &mut SocketSet, - timestamp: Instant, - ) -> Option; + fn poll(&mut self, iface: &mut Interface, sockets: &mut SocketSet, timestamp: Instant) + -> Event; } diff --git a/embassy-net/src/config/statik.rs b/embassy-net/src/config/statik.rs index 52196f48a..912143bff 100644 --- a/embassy-net/src/config/statik.rs +++ b/embassy-net/src/config/statik.rs @@ -5,12 +5,16 @@ use crate::fmt::*; use crate::{Interface, SocketSet}; pub struct StaticConfigurator { - config: UpConfig, + config: Config, + returned: bool, } impl StaticConfigurator { - pub fn new(config: UpConfig) -> Self { - Self { config } + pub fn new(config: Config) -> Self { + Self { + config, + returned: false, + } } } @@ -20,7 +24,12 @@ impl Configurator for StaticConfigurator { _iface: &mut Interface, _sockets: &mut SocketSet, _timestamp: Instant, - ) -> Option { - Some(Config::Up(self.config.clone())) + ) -> Event { + if self.returned { + Event::NoChange + } else { + self.returned = true; + Event::Configured(self.config.clone()) + } } } diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 32b56e5be..6c06b0605 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -4,6 +4,7 @@ use smoltcp::phy::DeviceCapabilities; use smoltcp::time::Instant as SmolInstant; use crate::fmt::*; +use crate::packet_pool::PacketBoxExt; use crate::Result; use crate::{Packet, PacketBox, PacketBuf}; diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index de2f2ea74..c79c38c0b 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -7,18 +7,19 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -mod pool; // TODO extract to embassy, or to own crate - mod config; mod device; mod packet_pool; mod stack; -mod tcp_socket; -pub use config::{Config, Configurator, DhcpConfigurator, StaticConfigurator, UpConfig}; +pub use config::{Config, Configurator, DhcpConfigurator, StaticConfigurator}; pub use device::{Device, LinkState}; -pub use packet_pool::{Packet, PacketBox, PacketBuf}; +pub use packet_pool::{Packet, PacketBox, PacketBoxExt, PacketBuf}; pub use stack::{init, is_init, run}; + +#[cfg(feature = "tcp")] +mod tcp_socket; +#[cfg(feature = "tcp")] pub use tcp_socket::TcpSocket; // smoltcp reexports @@ -28,4 +29,4 @@ pub use smoltcp::time::Instant as SmolInstant; pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; pub type Interface = smoltcp::iface::Interface<'static, device::DeviceAdapter>; pub type SocketSet = smoltcp::socket::SocketSet<'static>; -pub use smoltcp::{Error, Result}; \ No newline at end of file +pub use smoltcp::{Error, Result}; diff --git a/embassy-net/src/packet_pool.rs b/embassy-net/src/packet_pool.rs index 246356431..2c27d4013 100644 --- a/embassy-net/src/packet_pool.rs +++ b/embassy-net/src/packet_pool.rs @@ -1,7 +1,7 @@ use as_slice::{AsMutSlice, AsSlice}; use core::ops::{Deref, DerefMut, Range}; -use super::pool::{BitPool, Box, StaticPool}; +use atomic_pool::{pool, Box}; pub const MTU: usize = 1514; pub const PACKET_POOL_SIZE: usize = 4; @@ -17,8 +17,12 @@ impl Packet { } } -impl Box { - pub fn slice(self, range: Range) -> PacketBuf { +pub trait PacketBoxExt { + fn slice(self, range: Range) -> PacketBuf; +} + +impl PacketBoxExt for PacketBox { + fn slice(self, range: Range) -> PacketBuf { PacketBuf { packet: self, range, diff --git a/embassy-net/src/pool.rs b/embassy-net/src/pool.rs deleted file mode 100644 index 3ab36e4cc..000000000 --- a/embassy-net/src/pool.rs +++ /dev/null @@ -1,245 +0,0 @@ -#![macro_use] - -use as_slice::{AsMutSlice, AsSlice}; -use core::cmp; -use core::fmt; -use core::hash::{Hash, Hasher}; -use core::mem::MaybeUninit; -use core::ops::{Deref, DerefMut}; -use core::sync::atomic::{AtomicU32, Ordering}; - -use crate::fmt::{assert, *}; - -struct AtomicBitset -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - used: [AtomicU32; (N + 31) / 32], -} - -impl AtomicBitset -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - const fn new() -> Self { - const Z: AtomicU32 = AtomicU32::new(0); - Self { - used: [Z; (N + 31) / 32], - } - } - - fn alloc(&self) -> Option { - for (i, val) in self.used.iter().enumerate() { - let res = val.fetch_update(Ordering::AcqRel, Ordering::Acquire, |val| { - let n = val.trailing_ones() as usize + i * 32; - if n >= N { - None - } else { - Some(val | (1 << n)) - } - }); - if let Ok(val) = res { - let n = val.trailing_ones() as usize + i * 32; - return Some(n); - } - } - None - } - fn free(&self, i: usize) { - assert!(i < N); - self.used[i / 32].fetch_and(!(1 << ((i % 32) as u32)), Ordering::AcqRel); - } -} - -pub trait Pool { - fn alloc(&self) -> Option<*mut T>; - unsafe fn free(&self, p: *mut T); -} - -pub struct BitPool -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - used: AtomicBitset, - data: MaybeUninit<[T; N]>, -} - -impl BitPool -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - pub const fn new() -> Self { - Self { - used: AtomicBitset::new(), - data: MaybeUninit::uninit(), - } - } -} - -impl Pool for BitPool -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - fn alloc(&self) -> Option<*mut T> { - let n = self.used.alloc()?; - let origin = self.data.as_ptr() as *mut T; - Some(unsafe { origin.add(n) }) - } - - /// safety: p must be a pointer obtained from self.alloc that hasn't been freed yet. - unsafe fn free(&self, p: *mut T) { - let origin = self.data.as_ptr() as *mut T; - let n = p.offset_from(origin); - assert!(n >= 0); - assert!((n as usize) < N); - self.used.free(n as usize); - } -} - -pub trait StaticPool: 'static { - type Item: 'static; - type Pool: Pool; - fn get() -> &'static Self::Pool; -} - -pub struct Box { - ptr: *mut P::Item, -} - -impl Box

{ - pub fn new(item: P::Item) -> Option { - let p = match P::get().alloc() { - Some(p) => p, - None => { - warn!("alloc failed!"); - return None; - } - }; - //trace!("allocated {:u32}", p as u32); - unsafe { p.write(item) }; - Some(Self { ptr: p }) - } -} - -impl Drop for Box

{ - fn drop(&mut self) { - unsafe { - //trace!("dropping {:u32}", self.ptr as u32); - self.ptr.drop_in_place(); - P::get().free(self.ptr); - }; - } -} - -unsafe impl Send for Box

where P::Item: Send {} - -unsafe impl Sync for Box

where P::Item: Sync {} - -unsafe impl stable_deref_trait::StableDeref for Box

{} - -impl AsSlice for Box

-where - P::Item: AsSlice, -{ - type Element = ::Element; - - fn as_slice(&self) -> &[Self::Element] { - self.deref().as_slice() - } -} - -impl AsMutSlice for Box

-where - P::Item: AsMutSlice, -{ - fn as_mut_slice(&mut self) -> &mut [Self::Element] { - self.deref_mut().as_mut_slice() - } -} - -impl Deref for Box

{ - type Target = P::Item; - - fn deref(&self) -> &P::Item { - unsafe { &*self.ptr } - } -} - -impl DerefMut for Box

{ - fn deref_mut(&mut self) -> &mut P::Item { - unsafe { &mut *self.ptr } - } -} - -impl fmt::Debug for Box

-where - P::Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ::fmt(self, f) - } -} - -impl fmt::Display for Box

-where - P::Item: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ::fmt(self, f) - } -} - -impl PartialEq for Box

-where - P::Item: PartialEq, -{ - fn eq(&self, rhs: &Box

) -> bool { - ::eq(self, rhs) - } -} - -impl Eq for Box

where P::Item: Eq {} - -impl PartialOrd for Box

-where - P::Item: PartialOrd, -{ - fn partial_cmp(&self, rhs: &Box

) -> Option { - ::partial_cmp(self, rhs) - } -} - -impl Ord for Box

-where - P::Item: Ord, -{ - fn cmp(&self, rhs: &Box

) -> cmp::Ordering { - ::cmp(self, rhs) - } -} - -impl Hash for Box

-where - P::Item: Hash, -{ - fn hash(&self, state: &mut H) - where - H: Hasher, - { - ::hash(self, state) - } -} - -macro_rules! pool { - ($vis:vis $name:ident: [$ty:ty; $size:expr]) => { - $vis struct $name; - impl StaticPool for $name { - type Item = $ty; - type Pool = BitPool<$ty, $size>; - fn get() -> &'static Self::Pool { - static POOL: BitPool<$ty, $size> = BitPool::new(); - &POOL - } - } - }; -} 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') 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 ccdcd9df17748effd5f8d929b2d44ff083197993 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Apr 2021 17:24:52 +0200 Subject: publish config::Event --- embassy-net/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index c79c38c0b..edfb2c26d 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -12,7 +12,9 @@ mod device; mod packet_pool; mod stack; -pub use config::{Config, Configurator, DhcpConfigurator, StaticConfigurator}; +pub use config::{ + Config, Configurator, DhcpConfigurator, Event as ConfigEvent, StaticConfigurator, +}; pub use device::{Device, LinkState}; pub use packet_pool::{Packet, PacketBox, PacketBoxExt, PacketBuf}; pub use stack::{init, is_init, run}; -- cgit From 439092dc5974ee06266fae14198e6a9f36732780 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Apr 2021 18:13:22 +0200 Subject: derive Eq for config --- embassy-net/src/config/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/config/mod.rs b/embassy-net/src/config/mod.rs index a090aaacf..16470f7e6 100644 --- a/embassy-net/src/config/mod.rs +++ b/embassy-net/src/config/mod.rs @@ -25,7 +25,7 @@ pub enum Event { Configured(Config), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Config { pub address: Ipv4Cidr, pub gateway: Option, -- 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/lib.rs | 7 ++++--- embassy-net/src/stack.rs | 23 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index edfb2c26d..efa5f3cb1 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -12,9 +12,10 @@ mod device; mod packet_pool; mod stack; -pub use config::{ - Config, Configurator, DhcpConfigurator, Event as ConfigEvent, StaticConfigurator, -}; +#[cfg(feature = "dhcpv4")] +pub use config::DhcpConfigurator; +pub use config::{Config, Configurator, Event as ConfigEvent, StaticConfigurator}; + pub use device::{Device, LinkState}; pub use packet_pool::{Packet, PacketBox, PacketBoxExt, PacketBuf}; pub use stack::{init, is_init, run}; 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/lib.rs | 2 +- embassy-net/src/stack.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index efa5f3cb1..13f14b836 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -18,7 +18,7 @@ pub use config::{Config, Configurator, Event as ConfigEvent, StaticConfigurator} pub use device::{Device, LinkState}; pub use packet_pool::{Packet, PacketBox, PacketBoxExt, PacketBuf}; -pub use stack::{init, is_init, run}; +pub use stack::{init, is_config_up, is_init, is_link_up, run}; #[cfg(feature = "tcp")] mod tcp_socket; 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 From 773c3570e76ad6a6e2b8b8d4984cd658c2470843 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 18 May 2021 17:07:05 +0200 Subject: Update deps --- embassy-net/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 13f14b836..88dcf0aa5 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,8 +1,4 @@ #![cfg_attr(not(feature = "std"), no_std)] -#![feature(const_fn)] -#![feature(const_generics)] -#![feature(const_evaluatable_checked)] -#![allow(incomplete_features)] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -- cgit From b4c11695cf43dcdd0aa7a35798a15c923c7844c4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 28 May 2021 22:34:07 +0200 Subject: Update smoltcp --- embassy-net/src/config/dhcp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'embassy-net/src') diff --git a/embassy-net/src/config/dhcp.rs b/embassy-net/src/config/dhcp.rs index 007c398b3..f0c144321 100644 --- a/embassy-net/src/config/dhcp.rs +++ b/embassy-net/src/config/dhcp.rs @@ -38,9 +38,9 @@ impl Configurator for DhcpConfigurator { } match socket.poll() { - Dhcpv4Event::NoChange => Event::NoChange, - Dhcpv4Event::Deconfigured => Event::Deconfigured, - Dhcpv4Event::Configured(config) => { + None => Event::NoChange, + Some(Dhcpv4Event::Deconfigured) => Event::Deconfigured, + Some(Dhcpv4Event::Configured(config)) => { let mut dns_servers = Vec::new(); for s in &config.dns_servers { if let Some(addr) = s { -- cgit