summaryrefslogtreecommitdiff
path: root/embassy-net
diff options
context:
space:
mode:
authorDario Nieuwenhuis <dirbaio@dirbaio.net>2021-04-07 19:06:45 +0200
committerDario Nieuwenhuis <dirbaio@dirbaio.net>2021-04-07 19:06:45 +0200
commit9c5a8b945a743e75d586fdc2ef857d7c2a038e7d (patch)
treec7e4c88840281b3b54fbda466c717a83094f8121 /embassy-net
parent9bee576fd241f019c363919b0c29551c6b8ee4b2 (diff)
downloadembassy-9c5a8b945a743e75d586fdc2ef857d7c2a038e7d.zip
Update to latest embassy, atomic-pool, smoltcp
Diffstat (limited to 'embassy-net')
-rw-r--r--embassy-net/Cargo.toml10
-rw-r--r--embassy-net/src/config/dhcp.rs75
-rw-r--r--embassy-net/src/config/mod.rs30
-rw-r--r--embassy-net/src/config/statik.rs19
-rw-r--r--embassy-net/src/device.rs1
-rw-r--r--embassy-net/src/lib.rs13
-rw-r--r--embassy-net/src/packet_pool.rs10
-rw-r--r--embassy-net/src/pool.rs245
-rw-r--r--embassy-net/src/stack.rs77
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) {