aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-04-07 19:06:45 +0200
committerDario Nieuwenhuis <[email protected]>2021-04-07 19:06:45 +0200
commit9c5a8b945a743e75d586fdc2ef857d7c2a038e7d (patch)
treec7e4c88840281b3b54fbda466c717a83094f8121
parent9bee576fd241f019c363919b0c29551c6b8ee4b2 (diff)
Update to latest embassy, atomic-pool, smoltcp
-rw-r--r--Cargo.toml10
-rw-r--r--embassy-net-examples/Cargo.toml5
-rw-r--r--embassy-net-examples/src/main.rs36
-rw-r--r--embassy-net-examples/src/tuntap.rs35
-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
13 files changed, 185 insertions, 381 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 7ab99c2e9..8ed84db99 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -42,8 +42,8 @@ opt-level = 0
42overflow-checks = false 42overflow-checks = false
43 43
44[patch.crates-io] 44[patch.crates-io]
45embassy = { git = "https://github.com/akiles/embassy" } 45embassy = { git = "https://github.com/embassy-rs/embassy" }
46embassy-std = { git = "https://github.com/akiles/embassy" } 46embassy-std = { git = "https://github.com/embassy-rs/embassy" }
47embassy-macros = { git = "https://github.com/akiles/embassy" } 47embassy-macros = { git = "https://github.com/embassy-rs/embassy" }
48embassy-traits = { git = "https://github.com/akiles/embassy" } 48embassy-traits = { git = "https://github.com/embassy-rs/embassy" }
49smoltcp = { git = "https://github.com/akiles/smoltcp" } \ No newline at end of file 49smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev="9ce3d9505ef5455bb049713b9262561d78ebf330" } \ No newline at end of file
diff --git a/embassy-net-examples/Cargo.toml b/embassy-net-examples/Cargo.toml
index 944e91914..796c44745 100644
--- a/embassy-net-examples/Cargo.toml
+++ b/embassy-net-examples/Cargo.toml
@@ -8,10 +8,11 @@ edition = "2018"
8heapless = { version = "0.5.6", default-features = false } 8heapless = { version = "0.5.6", default-features = false }
9embassy = { version = "0.1.0", features=["std", "log"] } 9embassy = { version = "0.1.0", features=["std", "log"] }
10embassy-std = { version = "0.1.0" } 10embassy-std = { version = "0.1.0" }
11embassy-net = { version = "0.1.0", path = "../embassy-net", features=["std", "log"] } 11embassy-net = { version = "0.1.0", path = "../embassy-net", features=["std", "log", "tcp", "dhcpv4"] }
12env_logger = "0.8.2" 12env_logger = "0.8.2"
13log = "0.4.11" 13log = "0.4.11"
14futures = "0.3.8" 14futures = "0.3.8"
15libc = "0.2.81" 15libc = "0.2.81"
16async-io = "1.3.1" 16async-io = "1.3.1"
17smoltcp = { version = "0.6.0", default-features = false } 17smoltcp = { version = "0.7.0", default-features = false }
18clap = { version = "3.0.0-beta.2", features = ["derive"] } \ No newline at end of file
diff --git a/embassy-net-examples/src/main.rs b/embassy-net-examples/src/main.rs
index dba1415b7..c157ea34e 100644
--- a/embassy-net-examples/src/main.rs
+++ b/embassy-net-examples/src/main.rs
@@ -1,6 +1,10 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2#![feature(min_type_alias_impl_trait)]
3#![feature(impl_trait_in_bindings)]
4#![allow(incomplete_features)]
2 5
3use embassy::executor::{task, Spawner}; 6use clap::{AppSettings, Clap};
7use embassy::executor::Spawner;
4use embassy::io::AsyncWriteExt; 8use embassy::io::AsyncWriteExt;
5use embassy::util::Forever; 9use embassy::util::Forever;
6use embassy_net::*; 10use embassy_net::*;
@@ -13,25 +17,39 @@ mod tuntap;
13use crate::tuntap::TunTapDevice; 17use crate::tuntap::TunTapDevice;
14 18
15static DEVICE: Forever<TunTapDevice> = Forever::new(); 19static DEVICE: Forever<TunTapDevice> = Forever::new();
16static CONFIG: Forever<StaticConfigurator> = Forever::new(); 20static CONFIG: Forever<DhcpConfigurator> = Forever::new();
17 21
18#[task] 22#[derive(Clap)]
23#[clap(version = "1.0")]
24#[clap(setting = AppSettings::ColoredHelp)]
25struct Opts {
26 /// TAP device name
27 #[clap(long, default_value = "tap0")]
28 tap: String,
29}
30
31#[embassy::task]
19async fn net_task() { 32async fn net_task() {
20 embassy_net::run().await 33 embassy_net::run().await
21} 34}
22 35
23#[task] 36#[embassy::task]
24async fn main_task(spawner: Spawner) { 37async fn main_task(spawner: Spawner) {
38 let opts: Opts = Opts::parse();
39
25 // Init network device 40 // Init network device
26 let device = TunTapDevice::new("tap0").unwrap(); 41 let device = TunTapDevice::new(&opts.tap).unwrap();
27 42
28 // Static IP configuration 43 // Static IP configuration
29 let config = StaticConfigurator::new(UpConfig { 44 let config = StaticConfigurator::new(Config {
30 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24), 45 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
31 dns_servers: Vec::new(), 46 dns_servers: Vec::new(),
32 gateway: Ipv4Address::new(192, 168, 69, 100), 47 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
33 }); 48 });
34 49
50 // DHCP configruation
51 let config = DhcpConfigurator::new();
52
35 // Init network stack 53 // Init network stack
36 embassy_net::init(DEVICE.put(device), CONFIG.put(config)); 54 embassy_net::init(DEVICE.put(device), CONFIG.put(config));
37 55
@@ -45,7 +63,7 @@ async fn main_task(spawner: Spawner) {
45 63
46 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); 64 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
47 65
48 let remote_endpoint = (Ipv4Address::new(192, 168, 69, 100), 8000); 66 let remote_endpoint = (Ipv4Address::new(192, 168, 69, 74), 8000);
49 info!("connecting to {:?}...", remote_endpoint); 67 info!("connecting to {:?}...", remote_endpoint);
50 let r = socket.connect(remote_endpoint).await; 68 let r = socket.connect(remote_endpoint).await;
51 if let Err(e) = r { 69 if let Err(e) = r {
diff --git a/embassy-net-examples/src/tuntap.rs b/embassy-net-examples/src/tuntap.rs
index b2117e81b..dd453deb3 100644
--- a/embassy-net-examples/src/tuntap.rs
+++ b/embassy-net-examples/src/tuntap.rs
@@ -1,5 +1,4 @@
1use async_io::Async; 1use async_io::Async;
2use embassy::util::WakerRegistration;
3use libc; 2use libc;
4use log::*; 3use log::*;
5use smoltcp::wire::EthernetFrame; 4use smoltcp::wire::EthernetFrame;
@@ -130,20 +129,21 @@ impl io::Write for TunTap {
130 129
131pub struct TunTapDevice { 130pub struct TunTapDevice {
132 device: Async<TunTap>, 131 device: Async<TunTap>,
133 waker: WakerRegistration, 132 waker: Option<Waker>,
134} 133}
135 134
136impl TunTapDevice { 135impl TunTapDevice {
137 pub fn new(name: &str) -> io::Result<TunTapDevice> { 136 pub fn new(name: &str) -> io::Result<TunTapDevice> {
138 Ok(Self { 137 Ok(Self {
139 device: Async::new(TunTap::new(name)?)?, 138 device: Async::new(TunTap::new(name)?)?,
140 waker: WakerRegistration::new(), 139 waker: None,
141 }) 140 })
142 } 141 }
143} 142}
144 143
145use core::task::Waker; 144use core::task::Waker;
146use embassy_net::{DeviceCapabilities, LinkState, Packet, PacketBox, PacketBuf}; 145use embassy_net::{DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf};
146use std::task::Context;
147 147
148impl crate::Device for TunTapDevice { 148impl crate::Device for TunTapDevice {
149 fn is_transmit_ready(&mut self) -> bool { 149 fn is_transmit_ready(&mut self) -> bool {
@@ -169,7 +169,8 @@ impl crate::Device for TunTapDevice {
169 return Some(pkt.slice(0..n)); 169 return Some(pkt.slice(0..n));
170 } 170 }
171 Err(e) if e.kind() == io::ErrorKind::WouldBlock => { 171 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
172 let ready = if let Some(mut cx) = self.waker.context() { 172 let ready = if let Some(w) = self.waker.as_ref() {
173 let mut cx = Context::from_waker(w);
173 let ready = self.device.poll_readable(&mut cx).is_ready(); 174 let ready = self.device.poll_readable(&mut cx).is_ready();
174 ready 175 ready
175 } else { 176 } else {
@@ -184,8 +185,28 @@ impl crate::Device for TunTapDevice {
184 } 185 }
185 } 186 }
186 187
187 fn register_waker(&mut self, waker: &Waker) { 188 fn register_waker(&mut self, w: &Waker) {
188 self.waker.register(waker) 189 match self.waker {
190 // Optimization: If both the old and new Wakers wake the same task, we can simply
191 // keep the old waker, skipping the clone. (In most executor implementations,
192 // cloning a waker is somewhat expensive, comparable to cloning an Arc).
193 Some(ref w2) if (w2.will_wake(w)) => {}
194 _ => {
195 // clone the new waker and store it
196 if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) {
197 // We had a waker registered for another task. Wake it, so the other task can
198 // reregister itself if it's still interested.
199 //
200 // If two tasks are waiting on the same thing concurrently, this will cause them
201 // to wake each other in a loop fighting over this WakerRegistration. This wastes
202 // CPU but things will still work.
203 //
204 // If the user wants to have two tasks waiting on the same thing they should use
205 // a more appropriate primitive that can store multiple wakers.
206 old_waker.wake()
207 }
208 }
209 }
189 } 210 }
190 211
191 fn capabilities(&mut self) -> DeviceCapabilities { 212 fn capabilities(&mut self) -> DeviceCapabilities {
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index de625018c..dccd7984d 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -12,6 +12,9 @@ defmt-info = []
12defmt-warn = [] 12defmt-warn = []
13defmt-error = [] 13defmt-error = []
14 14
15tcp = ["smoltcp/socket-tcp"]
16dhcpv4 = ["smoltcp/socket-dhcpv4"]
17
15[dependencies] 18[dependencies]
16 19
17defmt = { version = "0.2.0", optional = true } 20defmt = { version = "0.2.0", optional = true }
@@ -25,9 +28,10 @@ as-slice = { version = "0.1.4" }
25generic-array = { version = "0.14.4", default-features = false } 28generic-array = { version = "0.14.4", default-features = false }
26stable_deref_trait = { version = "1.2.0", default-features = false } 29stable_deref_trait = { version = "1.2.0", default-features = false }
27futures = { version = "0.3.5", default-features = false, features = [ "async-await" ]} 30futures = { version = "0.3.5", default-features = false, features = [ "async-await" ]}
31atomic-pool = "0.1.0"
28 32
29[dependencies.smoltcp] 33[dependencies.smoltcp]
30version = "0.6.0" 34version = "0.7.0"
31#git = "https://github.com/akiles/smoltcp" 35#git = "https://github.com/akiles/smoltcp"
32#rev = "00952e2c5cdf5667a1dfb6142258055f58d3851c" 36#rev = "00952e2c5cdf5667a1dfb6142258055f58d3851c"
33default-features = false 37default-features = false
@@ -35,12 +39,12 @@ features = [
35 "medium-ethernet", 39 "medium-ethernet",
36 "medium-ip", 40 "medium-ip",
37 "proto-ipv4", 41 "proto-ipv4",
38 "proto-dhcpv4", 42 #"proto-dhcpv4",
39 #"proto-igmp", 43 #"proto-igmp",
40 #"proto-ipv6", 44 #"proto-ipv6",
41 #"socket-raw", 45 #"socket-raw",
42 #"socket-icmp", 46 #"socket-icmp",
43 #"socket-udp", 47 #"socket-udp",
44 "socket-tcp", 48 #"socket-tcp",
45 "async", 49 "async",
46] 50]
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 @@
1use embassy::util::Forever;
2use heapless::Vec; 1use heapless::Vec;
3use smoltcp::dhcp::Dhcpv4Client; 2use smoltcp::socket::{Dhcpv4Event, Dhcpv4Socket, SocketHandle};
4use smoltcp::socket::{RawPacketMetadata, RawSocketBuffer};
5use smoltcp::time::Instant; 3use smoltcp::time::Instant;
6use smoltcp::wire::Ipv4Address;
7 4
8use super::*; 5use super::*;
9use crate::device::LinkState; 6use crate::device::LinkState;
10use crate::fmt::*; 7use crate::fmt::*;
11use crate::{Interface, SocketSet}; 8use crate::{Interface, SocketSet};
12 9
13pub struct DhcpResources {
14 rx_buffer: [u8; 900],
15 tx_buffer: [u8; 600],
16 rx_meta: [RawPacketMetadata; 1],
17 tx_meta: [RawPacketMetadata; 1],
18}
19
20pub struct DhcpConfigurator { 10pub struct DhcpConfigurator {
21 client: Option<Dhcpv4Client>, 11 handle: Option<SocketHandle>,
22} 12}
23 13
24impl DhcpConfigurator { 14impl DhcpConfigurator {
25 pub fn new() -> Self { 15 pub fn new() -> Self {
26 Self { client: None } 16 Self { handle: None }
27 } 17 }
28} 18}
29 19
30static DHCP_RESOURCES: Forever<DhcpResources> = Forever::new();
31
32impl Configurator for DhcpConfigurator { 20impl Configurator for DhcpConfigurator {
33 fn poll( 21 fn poll(
34 &mut self, 22 &mut self,
35 iface: &mut Interface, 23 iface: &mut Interface,
36 sockets: &mut SocketSet, 24 sockets: &mut SocketSet,
37 timestamp: Instant, 25 _timestamp: Instant,
38 ) -> Option<Config> { 26 ) -> Event {
39 if self.client.is_none() { 27 if self.handle.is_none() {
40 let res = DHCP_RESOURCES.put(DhcpResources { 28 let handle = sockets.add(Dhcpv4Socket::new());
41 rx_buffer: [0; 900], 29 self.handle = Some(handle)
42 tx_buffer: [0; 600],
43 rx_meta: [RawPacketMetadata::EMPTY; 1],
44 tx_meta: [RawPacketMetadata::EMPTY; 1],
45 });
46 let rx_buffer = RawSocketBuffer::new(&mut res.rx_meta[..], &mut res.rx_buffer[..]);
47 let tx_buffer = RawSocketBuffer::new(&mut res.tx_meta[..], &mut res.tx_buffer[..]);
48 let dhcp = Dhcpv4Client::new(sockets, rx_buffer, tx_buffer, timestamp);
49 info!("created dhcp");
50 self.client = Some(dhcp)
51 } 30 }
52 31
53 let client = self.client.as_mut().unwrap(); 32 let mut socket = sockets.get::<Dhcpv4Socket>(self.handle.unwrap());
54 33
55 let link_up = iface.device_mut().device.link_state() == LinkState::Up; 34 let link_up = iface.device_mut().device.link_state() == LinkState::Up;
56 if !link_up { 35 if !link_up {
57 client.reset(timestamp); 36 socket.reset();
58 return Some(Config::Down); 37 return Event::Deconfigured;
59 } 38 }
60 39
61 let config = client.poll(iface, sockets, timestamp).unwrap_or(None)?; 40 match socket.poll() {
62 41 Dhcpv4Event::NoChange => Event::NoChange,
63 if config.address.is_none() { 42 Dhcpv4Event::Deconfigured => Event::Deconfigured,
64 return Some(Config::Down); 43 Dhcpv4Event::Configured(config) => {
65 } 44 let mut dns_servers = Vec::new();
66 45 for s in &config.dns_servers {
67 let mut dns_servers = Vec::new(); 46 if let Some(addr) = s {
68 for s in &config.dns_servers { 47 dns_servers.push(addr.clone()).unwrap();
69 if let Some(addr) = s { 48 }
70 dns_servers.push(addr.clone()).unwrap(); 49 }
50
51 Event::Configured(Config {
52 address: config.address,
53 gateway: config.router,
54 dns_servers,
55 })
71 } 56 }
72 } 57 }
73
74 return Some(Config::Up(UpConfig {
75 address: config.address.unwrap(),
76 gateway: config.router.unwrap_or(Ipv4Address::UNSPECIFIED),
77 dns_servers,
78 }));
79 } 58 }
80} 59}
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};
6use crate::fmt::*; 6use crate::fmt::*;
7use crate::{Interface, SocketSet}; 7use crate::{Interface, SocketSet};
8 8
9mod dhcp;
10mod statik; 9mod statik;
11pub use dhcp::DhcpConfigurator;
12pub use statik::StaticConfigurator; 10pub use statik::StaticConfigurator;
13 11
12#[cfg(feature = "dhcpv4")]
13mod dhcp;
14#[cfg(feature = "dhcpv4")]
15pub use dhcp::DhcpConfigurator;
16
17/// Return value for the `Configurator::poll` function
14#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
15pub enum Config { 19pub enum Event {
16 Down, 20 /// No change has occured to the configuration.
17 Up(UpConfig), 21 NoChange,
22 /// Configuration has been lost (for example, DHCP lease has expired)
23 Deconfigured,
24 /// Configuration has been newly acquired, or modified.
25 Configured(Config),
18} 26}
19 27
20#[derive(Debug, Clone)] 28#[derive(Debug, Clone)]
21pub struct UpConfig { 29pub struct Config {
22 pub address: Ipv4Cidr, 30 pub address: Ipv4Cidr,
23 pub gateway: Ipv4Address, 31 pub gateway: Option<Ipv4Address>,
24 pub dns_servers: Vec<Ipv4Address, U3>, 32 pub dns_servers: Vec<Ipv4Address, U3>,
25} 33}
26 34
27pub trait Configurator { 35pub trait Configurator {
28 fn poll( 36 fn poll(&mut self, iface: &mut Interface, sockets: &mut SocketSet, timestamp: Instant)
29 &mut self, 37 -> Event;
30 iface: &mut Interface,
31 sockets: &mut SocketSet,
32 timestamp: Instant,
33 ) -> Option<Config>;
34} 38}
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::*;
5use crate::{Interface, SocketSet}; 5use crate::{Interface, SocketSet};
6 6
7pub struct StaticConfigurator { 7pub struct StaticConfigurator {
8 config: UpConfig, 8 config: Config,
9 returned: bool,
9} 10}
10 11
11impl StaticConfigurator { 12impl StaticConfigurator {
12 pub fn new(config: UpConfig) -> Self { 13 pub fn new(config: Config) -> Self {
13 Self { config } 14 Self {
15 config,
16 returned: false,
17 }
14 } 18 }
15} 19}
16 20
@@ -20,7 +24,12 @@ impl Configurator for StaticConfigurator {
20 _iface: &mut Interface, 24 _iface: &mut Interface,
21 _sockets: &mut SocketSet, 25 _sockets: &mut SocketSet,
22 _timestamp: Instant, 26 _timestamp: Instant,
23 ) -> Option<Config> { 27 ) -> Event {
24 Some(Config::Up(self.config.clone())) 28 if self.returned {
29 Event::NoChange
30 } else {
31 self.returned = true;
32 Event::Configured(self.config.clone())
33 }
25 } 34 }
26} 35}
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;
4use smoltcp::time::Instant as SmolInstant; 4use smoltcp::time::Instant as SmolInstant;
5 5
6use crate::fmt::*; 6use crate::fmt::*;
7use crate::packet_pool::PacketBoxExt;
7use crate::Result; 8use crate::Result;
8use crate::{Packet, PacketBox, PacketBuf}; 9use crate::{Packet, PacketBox, PacketBuf};
9 10
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 @@
7// This mod MUST go first, so that the others see its macros. 7// This mod MUST go first, so that the others see its macros.
8pub(crate) mod fmt; 8pub(crate) mod fmt;
9 9
10mod pool; // TODO extract to embassy, or to own crate
11
12mod config; 10mod config;
13mod device; 11mod device;
14mod packet_pool; 12mod packet_pool;
15mod stack; 13mod stack;
16mod tcp_socket;
17 14
18pub use config::{Config, Configurator, DhcpConfigurator, StaticConfigurator, UpConfig}; 15pub use config::{Config, Configurator, DhcpConfigurator, StaticConfigurator};
19pub use device::{Device, LinkState}; 16pub use device::{Device, LinkState};
20pub use packet_pool::{Packet, PacketBox, PacketBuf}; 17pub use packet_pool::{Packet, PacketBox, PacketBoxExt, PacketBuf};
21pub use stack::{init, is_init, run}; 18pub use stack::{init, is_init, run};
19
20#[cfg(feature = "tcp")]
21mod tcp_socket;
22#[cfg(feature = "tcp")]
22pub use tcp_socket::TcpSocket; 23pub use tcp_socket::TcpSocket;
23 24
24// smoltcp reexports 25// smoltcp reexports
@@ -28,4 +29,4 @@ pub use smoltcp::time::Instant as SmolInstant;
28pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; 29pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr};
29pub type Interface = smoltcp::iface::Interface<'static, device::DeviceAdapter>; 30pub type Interface = smoltcp::iface::Interface<'static, device::DeviceAdapter>;
30pub type SocketSet = smoltcp::socket::SocketSet<'static>; 31pub type SocketSet = smoltcp::socket::SocketSet<'static>;
31pub use smoltcp::{Error, Result}; \ No newline at end of file 32pub 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 @@
1use as_slice::{AsMutSlice, AsSlice}; 1use as_slice::{AsMutSlice, AsSlice};
2use core::ops::{Deref, DerefMut, Range}; 2use core::ops::{Deref, DerefMut, Range};
3 3
4use super::pool::{BitPool, Box, StaticPool}; 4use atomic_pool::{pool, Box};
5 5
6pub const MTU: usize = 1514; 6pub const MTU: usize = 1514;
7pub const PACKET_POOL_SIZE: usize = 4; 7pub const PACKET_POOL_SIZE: usize = 4;
@@ -17,8 +17,12 @@ impl Packet {
17 } 17 }
18} 18}
19 19
20impl Box<PacketPool> { 20pub trait PacketBoxExt {
21 pub fn slice(self, range: Range<usize>) -> PacketBuf { 21 fn slice(self, range: Range<usize>) -> PacketBuf;
22}
23
24impl PacketBoxExt for PacketBox {
25 fn slice(self, range: Range<usize>) -> PacketBuf {
22 PacketBuf { 26 PacketBuf {
23 packet: self, 27 packet: self,
24 range, 28 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 @@
1#![macro_use]
2
3use as_slice::{AsMutSlice, AsSlice};
4use core::cmp;
5use core::fmt;
6use core::hash::{Hash, Hasher};
7use core::mem::MaybeUninit;
8use core::ops::{Deref, DerefMut};
9use core::sync::atomic::{AtomicU32, Ordering};
10
11use crate::fmt::{assert, *};
12
13struct AtomicBitset<const N: usize>
14where
15 [AtomicU32; (N + 31) / 32]: Sized,
16{
17 used: [AtomicU32; (N + 31) / 32],
18}
19
20impl<const N: usize> AtomicBitset<N>
21where
22 [AtomicU32; (N + 31) / 32]: Sized,
23{
24 const fn new() -> Self {
25 const Z: AtomicU32 = AtomicU32::new(0);
26 Self {
27 used: [Z; (N + 31) / 32],
28 }
29 }
30
31 fn alloc(&self) -> Option<usize> {
32 for (i, val) in self.used.iter().enumerate() {
33 let res = val.fetch_update(Ordering::AcqRel, Ordering::Acquire, |val| {
34 let n = val.trailing_ones() as usize + i * 32;
35 if n >= N {
36 None
37 } else {
38 Some(val | (1 << n))
39 }
40 });
41 if let Ok(val) = res {
42 let n = val.trailing_ones() as usize + i * 32;
43 return Some(n);
44 }
45 }
46 None
47 }
48 fn free(&self, i: usize) {
49 assert!(i < N);
50 self.used[i / 32].fetch_and(!(1 << ((i % 32) as u32)), Ordering::AcqRel);
51 }
52}
53
54pub trait Pool<T> {
55 fn alloc(&self) -> Option<*mut T>;
56 unsafe fn free(&self, p: *mut T);
57}
58
59pub struct BitPool<T, const N: usize>
60where
61 [AtomicU32; (N + 31) / 32]: Sized,
62{
63 used: AtomicBitset<N>,
64 data: MaybeUninit<[T; N]>,
65}
66
67impl<T, const N: usize> BitPool<T, N>
68where
69 [AtomicU32; (N + 31) / 32]: Sized,
70{
71 pub const fn new() -> Self {
72 Self {
73 used: AtomicBitset::new(),
74 data: MaybeUninit::uninit(),
75 }
76 }
77}
78
79impl<T, const N: usize> Pool<T> for BitPool<T, N>
80where
81 [AtomicU32; (N + 31) / 32]: Sized,
82{
83 fn alloc(&self) -> Option<*mut T> {
84 let n = self.used.alloc()?;
85 let origin = self.data.as_ptr() as *mut T;
86 Some(unsafe { origin.add(n) })
87 }
88
89 /// safety: p must be a pointer obtained from self.alloc that hasn't been freed yet.
90 unsafe fn free(&self, p: *mut T) {
91 let origin = self.data.as_ptr() as *mut T;
92 let n = p.offset_from(origin);
93 assert!(n >= 0);
94 assert!((n as usize) < N);
95 self.used.free(n as usize);
96 }
97}
98
99pub trait StaticPool: 'static {
100 type Item: 'static;
101 type Pool: Pool<Self::Item>;
102 fn get() -> &'static Self::Pool;
103}
104
105pub struct Box<P: StaticPool> {
106 ptr: *mut P::Item,
107}
108
109impl<P: StaticPool> Box<P> {
110 pub fn new(item: P::Item) -> Option<Self> {
111 let p = match P::get().alloc() {
112 Some(p) => p,
113 None => {
114 warn!("alloc failed!");
115 return None;
116 }
117 };
118 //trace!("allocated {:u32}", p as u32);
119 unsafe { p.write(item) };
120 Some(Self { ptr: p })
121 }
122}
123
124impl<P: StaticPool> Drop for Box<P> {
125 fn drop(&mut self) {
126 unsafe {
127 //trace!("dropping {:u32}", self.ptr as u32);
128 self.ptr.drop_in_place();
129 P::get().free(self.ptr);
130 };
131 }
132}
133
134unsafe impl<P: StaticPool> Send for Box<P> where P::Item: Send {}
135
136unsafe impl<P: StaticPool> Sync for Box<P> where P::Item: Sync {}
137
138unsafe impl<P: StaticPool> stable_deref_trait::StableDeref for Box<P> {}
139
140impl<P: StaticPool> AsSlice for Box<P>
141where
142 P::Item: AsSlice,
143{
144 type Element = <P::Item as AsSlice>::Element;
145
146 fn as_slice(&self) -> &[Self::Element] {
147 self.deref().as_slice()
148 }
149}
150
151impl<P: StaticPool> AsMutSlice for Box<P>
152where
153 P::Item: AsMutSlice,
154{
155 fn as_mut_slice(&mut self) -> &mut [Self::Element] {
156 self.deref_mut().as_mut_slice()
157 }
158}
159
160impl<P: StaticPool> Deref for Box<P> {
161 type Target = P::Item;
162
163 fn deref(&self) -> &P::Item {
164 unsafe { &*self.ptr }
165 }
166}
167
168impl<P: StaticPool> DerefMut for Box<P> {
169 fn deref_mut(&mut self) -> &mut P::Item {
170 unsafe { &mut *self.ptr }
171 }
172}
173
174impl<P: StaticPool> fmt::Debug for Box<P>
175where
176 P::Item: fmt::Debug,
177{
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 <P::Item as fmt::Debug>::fmt(self, f)
180 }
181}
182
183impl<P: StaticPool> fmt::Display for Box<P>
184where
185 P::Item: fmt::Display,
186{
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 <P::Item as fmt::Display>::fmt(self, f)
189 }
190}
191
192impl<P: StaticPool> PartialEq for Box<P>
193where
194 P::Item: PartialEq,
195{
196 fn eq(&self, rhs: &Box<P>) -> bool {
197 <P::Item as PartialEq>::eq(self, rhs)
198 }
199}
200
201impl<P: StaticPool> Eq for Box<P> where P::Item: Eq {}
202
203impl<P: StaticPool> PartialOrd for Box<P>
204where
205 P::Item: PartialOrd,
206{
207 fn partial_cmp(&self, rhs: &Box<P>) -> Option<cmp::Ordering> {
208 <P::Item as PartialOrd>::partial_cmp(self, rhs)
209 }
210}
211
212impl<P: StaticPool> Ord for Box<P>
213where
214 P::Item: Ord,
215{
216 fn cmp(&self, rhs: &Box<P>) -> cmp::Ordering {
217 <P::Item as Ord>::cmp(self, rhs)
218 }
219}
220
221impl<P: StaticPool> Hash for Box<P>
222where
223 P::Item: Hash,
224{
225 fn hash<H>(&self, state: &mut H)
226 where
227 H: Hasher,
228 {
229 <P::Item as Hash>::hash(self, state)
230 }
231}
232
233macro_rules! pool {
234 ($vis:vis $name:ident: [$ty:ty; $size:expr]) => {
235 $vis struct $name;
236 impl StaticPool for $name {
237 type Item = $ty;
238 type Pool = BitPool<$ty, $size>;
239 fn get() -> &'static Self::Pool {
240 static POOL: BitPool<$ty, $size> = BitPool::new();
241 &POOL
242 }
243 }
244 };
245}
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 _;
11use smoltcp::phy::Medium; 11use smoltcp::phy::Medium;
12use smoltcp::socket::SocketSetItem; 12use smoltcp::socket::SocketSetItem;
13use smoltcp::time::Instant as SmolInstant; 13use smoltcp::time::Instant as SmolInstant;
14use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; 14use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr};
15 15
16use crate::device::{Device, DeviceAdapter}; 16use crate::config::Configurator;
17use crate::config::Event;
18use crate::device::{Device, DeviceAdapter, LinkState};
17use crate::fmt::*; 19use crate::fmt::*;
18use crate::{
19 config::{Config, Configurator},
20 device::LinkState,
21};
22use crate::{Interface, SocketSet}; 20use crate::{Interface, SocketSet};
23 21
24const ADDRESSES_LEN: usize = 1; 22const ADDRESSES_LEN: usize = 1;
@@ -68,39 +66,41 @@ impl Stack {
68 } 66 }
69 67
70 fn poll_configurator(&mut self, timestamp: SmolInstant) { 68 fn poll_configurator(&mut self, timestamp: SmolInstant) {
71 if let Some(config) = self 69 let medium = self.iface.device().capabilities().medium;
70
71 match self
72 .configurator 72 .configurator
73 .poll(&mut self.iface, &mut self.sockets, timestamp) 73 .poll(&mut self.iface, &mut self.sockets, timestamp)
74 { 74 {
75 let medium = self.iface.device().capabilities().medium; 75 Event::NoChange => {}
76 76 Event::Configured(config) => {
77 let (addr, gateway) = match config { 77 debug!("Acquired IP configuration:");
78 Config::Up(config) => (config.address.into(), Some(config.gateway)), 78
79 Config::Down => (IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32), None), 79 debug!(" IP address: {}", config.address);
80 }; 80 set_ipv4_addr(&mut self.iface, config.address);
81 81
82 self.iface.update_ip_addrs(|addrs| { 82 if medium == Medium::Ethernet {
83 let curr_addr = &mut addrs[0]; 83 if let Some(gateway) = config.gateway {
84 if *curr_addr != addr { 84 debug!(" Default gateway: {}", gateway);
85 info!("IPv4 address: {:?} -> {:?}", *curr_addr, addr); 85 self.iface
86 *curr_addr = addr; 86 .routes_mut()
87 } 87 .add_default_ipv4_route(gateway)
88 }); 88 .unwrap();
89 89 } else {
90 if medium == Medium::Ethernet { 90 debug!(" Default gateway: None");
91 self.iface.routes_mut().update(|r| { 91 self.iface.routes_mut().remove_default_ipv4_route();
92 let cidr = IpCidr::new(IpAddress::v4(0, 0, 0, 0), 0);
93 let curr_gateway = r.get(&cidr).map(|r| r.via_router);
94
95 if curr_gateway != gateway.map(|a| a.into()) {
96 info!("IPv4 gateway: {:?} -> {:?}", curr_gateway, gateway);
97 if let Some(gateway) = gateway {
98 r.insert(cidr, Route::new_ipv4_gateway(gateway)).unwrap();
99 } else {
100 r.remove(&cidr);
101 }
102 } 92 }
103 }); 93 }
94 for (i, s) in config.dns_servers.iter().enumerate() {
95 debug!(" DNS server {}: {}", i, s);
96 }
97 }
98 Event::Deconfigured => {
99 debug!("Lost IP configuration");
100 set_ipv4_addr(&mut self.iface, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0));
101 if medium == Medium::Ethernet {
102 self.iface.routes_mut().remove_default_ipv4_route();
103 }
104 } 104 }
105 } 105 }
106 } 106 }
@@ -143,6 +143,13 @@ impl Stack {
143 } 143 }
144} 144}
145 145
146fn set_ipv4_addr(iface: &mut Interface, cidr: Ipv4Cidr) {
147 iface.update_ip_addrs(|addrs| {
148 let dest = addrs.iter_mut().next().unwrap();
149 *dest = IpCidr::Ipv4(cidr);
150 });
151}
152
146/// Initialize embassy_net. 153/// Initialize embassy_net.
147/// This function must be called from thread mode. 154/// This function must be called from thread mode.
148pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Configurator) { 155pub fn init(device: &'static mut dyn Device, configurator: &'static mut dyn Configurator) {