diff options
author | Dario Nieuwenhuis <dirbaio@dirbaio.net> | 2021-04-07 19:06:45 +0200 |
---|---|---|
committer | Dario Nieuwenhuis <dirbaio@dirbaio.net> | 2021-04-07 19:06:45 +0200 |
commit | 9c5a8b945a743e75d586fdc2ef857d7c2a038e7d (patch) | |
tree | c7e4c88840281b3b54fbda466c717a83094f8121 /embassy-net | |
parent | 9bee576fd241f019c363919b0c29551c6b8ee4b2 (diff) | |
download | embassy-9c5a8b945a743e75d586fdc2ef857d7c2a038e7d.zip |
Update to latest embassy, atomic-pool, smoltcp
Diffstat (limited to 'embassy-net')
-rw-r--r-- | embassy-net/Cargo.toml | 10 | ||||
-rw-r--r-- | embassy-net/src/config/dhcp.rs | 75 | ||||
-rw-r--r-- | embassy-net/src/config/mod.rs | 30 | ||||
-rw-r--r-- | embassy-net/src/config/statik.rs | 19 | ||||
-rw-r--r-- | embassy-net/src/device.rs | 1 | ||||
-rw-r--r-- | embassy-net/src/lib.rs | 13 | ||||
-rw-r--r-- | embassy-net/src/packet_pool.rs | 10 | ||||
-rw-r--r-- | embassy-net/src/pool.rs | 245 | ||||
-rw-r--r-- | embassy-net/src/stack.rs | 77 |
9 files changed, 122 insertions, 358 deletions
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index de625018..dccd7984 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -12,6 +12,9 @@ defmt-info = [] defmt-warn = [] defmt-error = [] +tcp = ["smoltcp/socket-tcp"] +dhcpv4 = ["smoltcp/socket-dhcpv4"] + [dependencies] defmt = { version = "0.2.0", optional = true } @@ -25,9 +28,10 @@ as-slice = { version = "0.1.4" } generic-array = { version = "0.14.4", default-features = false } stable_deref_trait = { version = "1.2.0", default-features = false } futures = { version = "0.3.5", default-features = false, features = [ "async-await" ]} +atomic-pool = "0.1.0" [dependencies.smoltcp] -version = "0.6.0" +version = "0.7.0" #git = "https://github.com/akiles/smoltcp" #rev = "00952e2c5cdf5667a1dfb6142258055f58d3851c" default-features = false @@ -35,12 +39,12 @@ features = [ "medium-ethernet", "medium-ip", "proto-ipv4", - "proto-dhcpv4", + #"proto-dhcpv4", #"proto-igmp", #"proto-ipv6", #"socket-raw", #"socket-icmp", #"socket-udp", - "socket-tcp", + #"socket-tcp", "async", ] diff --git a/embassy-net/src/config/dhcp.rs b/embassy-net/src/config/dhcp.rs index 0df67baf..007c398b 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<Dhcpv4Client>, + handle: Option<SocketHandle>, } impl DhcpConfigurator { pub fn new() -> Self { - Self { client: None } + Self { handle: None } } } -static DHCP_RESOURCES: Forever<DhcpResources> = Forever::new(); - impl Configurator for DhcpConfigurator { fn poll( &mut self, iface: &mut Interface, sockets: &mut SocketSet, - timestamp: Instant, - ) -> Option<Config> { - 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::<Dhcpv4Socket>(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 596374f9..a090aaac 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<Ipv4Address>, pub dns_servers: Vec<Ipv4Address, U3>, } pub trait Configurator { - fn poll( - &mut self, - iface: &mut Interface, - sockets: &mut SocketSet, - timestamp: Instant, - ) -> Option<Config>; + 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 52196f48..912143bf 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<Config> { - 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 32b56e5b..6c06b060 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 de2f2ea7..c79c38c0 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 24635643..2c27d401 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<PacketPool> { - pub fn slice(self, range: Range<usize>) -> PacketBuf { +pub trait PacketBoxExt { + fn slice(self, range: Range<usize>) -> PacketBuf; +} + +impl PacketBoxExt for PacketBox { + fn slice(self, range: Range<usize>) -> PacketBuf { PacketBuf { packet: self, range, diff --git a/embassy-net/src/pool.rs b/embassy-net/src/pool.rs deleted file mode 100644 index 3ab36e4c..00000000 --- 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<const N: usize> -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - used: [AtomicU32; (N + 31) / 32], -} - -impl<const N: usize> AtomicBitset<N> -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<usize> { - 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<T> { - fn alloc(&self) -> Option<*mut T>; - unsafe fn free(&self, p: *mut T); -} - -pub struct BitPool<T, const N: usize> -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - used: AtomicBitset<N>, - data: MaybeUninit<[T; N]>, -} - -impl<T, const N: usize> BitPool<T, N> -where - [AtomicU32; (N + 31) / 32]: Sized, -{ - pub const fn new() -> Self { - Self { - used: AtomicBitset::new(), - data: MaybeUninit::uninit(), - } - } -} - -impl<T, const N: usize> Pool<T> for BitPool<T, N> -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<Self::Item>; - fn get() -> &'static Self::Pool; -} - -pub struct Box<P: StaticPool> { - ptr: *mut P::Item, -} - -impl<P: StaticPool> Box<P> { - pub fn new(item: P::Item) -> Option<Self> { - 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<P: StaticPool> Drop for Box<P> { - fn drop(&mut self) { - unsafe { - //trace!("dropping {:u32}", self.ptr as u32); - self.ptr.drop_in_place(); - P::get().free(self.ptr); - }; - } -} - -unsafe impl<P: StaticPool> Send for Box<P> where P::Item: Send {} - -unsafe impl<P: StaticPool> Sync for Box<P> where P::Item: Sync {} - -unsafe impl<P: StaticPool> stable_deref_trait::StableDeref for Box<P> {} - -impl<P: StaticPool> AsSlice for Box<P> -where - P::Item: AsSlice, -{ - type Element = <P::Item as AsSlice>::Element; - - fn as_slice(&self) -> &[Self::Element] { - self.deref().as_slice() - } -} - -impl<P: StaticPool> AsMutSlice for Box<P> -where - P::Item: AsMutSlice, -{ - fn as_mut_slice(&mut self) -> &mut [Self::Element] { - self.deref_mut().as_mut_slice() - } -} - -impl<P: StaticPool> Deref for Box<P> { - type Target = P::Item; - - fn deref(&self) -> &P::Item { - unsafe { &*self.ptr } - } -} - -impl<P: StaticPool> DerefMut for Box<P> { - fn deref_mut(&mut self) -> &mut P::Item { - unsafe { &mut *self.ptr } - } -} - -impl<P: StaticPool> fmt::Debug for Box<P> -where - P::Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - <P::Item as fmt::Debug>::fmt(self, f) - } -} - -impl<P: StaticPool> fmt::Display for Box<P> -where - P::Item: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - <P::Item as fmt::Display>::fmt(self, f) - } -} - -impl<P: StaticPool> PartialEq for Box<P> -where - P::Item: PartialEq, -{ - fn eq(&self, rhs: &Box<P>) -> bool { - <P::Item as PartialEq>::eq(self, rhs) - } -} - -impl<P: StaticPool> Eq for Box<P> where P::Item: Eq {} - -impl<P: StaticPool> PartialOrd for Box<P> -where - P::Item: PartialOrd, -{ - fn partial_cmp(&self, rhs: &Box<P>) -> Option<cmp::Ordering> { - <P::Item as PartialOrd>::partial_cmp(self, rhs) - } -} - -impl<P: StaticPool> Ord for Box<P> -where - P::Item: Ord, -{ - fn cmp(&self, rhs: &Box<P>) -> cmp::Ordering { - <P::Item as Ord>::cmp(self, rhs) - } -} - -impl<P: StaticPool> Hash for Box<P> -where - P::Item: Hash, -{ - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - <P::Item as Hash>::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 f8a945a5..dc8043e6 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) { |