diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-12-07 16:02:28 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-12-13 16:18:39 +0100 |
| commit | aaaf5f23a8a3a0df1ad2186802e2afc061a74b72 (patch) | |
| tree | 05fa84ad745c1b9d3e712ef65e79076c37d92601 /embassy-net | |
| parent | ac74613b5a7be72acd8d5259055963f8b4aba7fd (diff) | |
net: move stack into lib.rs
Diffstat (limited to 'embassy-net')
| -rw-r--r-- | embassy-net/src/lib.rs | 307 | ||||
| -rw-r--r-- | embassy-net/src/stack.rs | 306 | ||||
| -rw-r--r-- | embassy-net/src/tcp.rs | 3 | ||||
| -rw-r--r-- | embassy-net/src/udp.rs | 3 |
4 files changed, 304 insertions, 315 deletions
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index e18e819cb..afe0d6da0 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs | |||
| @@ -9,16 +9,28 @@ | |||
| 9 | pub(crate) mod fmt; | 9 | pub(crate) mod fmt; |
| 10 | 10 | ||
| 11 | pub mod device; | 11 | pub mod device; |
| 12 | mod stack; | ||
| 13 | |||
| 14 | pub use stack::{Config, ConfigStrategy, Stack, StackResources}; | ||
| 15 | |||
| 16 | #[cfg(feature = "tcp")] | 12 | #[cfg(feature = "tcp")] |
| 17 | pub mod tcp; | 13 | pub mod tcp; |
| 18 | |||
| 19 | #[cfg(feature = "udp")] | 14 | #[cfg(feature = "udp")] |
| 20 | pub mod udp; | 15 | pub mod udp; |
| 21 | 16 | ||
| 17 | use core::cell::RefCell; | ||
| 18 | use core::future::{poll_fn, Future}; | ||
| 19 | use core::task::{Context, Poll}; | ||
| 20 | |||
| 21 | use embassy_sync::waitqueue::WakerRegistration; | ||
| 22 | use embassy_time::{Instant, Timer}; | ||
| 23 | use futures::pin_mut; | ||
| 24 | use heapless::Vec; | ||
| 25 | #[cfg(feature = "dhcpv4")] | ||
| 26 | use smoltcp::iface::SocketHandle; | ||
| 27 | use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage}; | ||
| 28 | #[cfg(feature = "medium-ethernet")] | ||
| 29 | use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes}; | ||
| 30 | #[cfg(feature = "medium-ethernet")] | ||
| 31 | use smoltcp::phy::Medium; | ||
| 32 | #[cfg(feature = "dhcpv4")] | ||
| 33 | use smoltcp::socket::dhcpv4; | ||
| 22 | // smoltcp reexports | 34 | // smoltcp reexports |
| 23 | pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant}; | 35 | pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant}; |
| 24 | #[cfg(feature = "medium-ethernet")] | 36 | #[cfg(feature = "medium-ethernet")] |
| @@ -28,3 +40,288 @@ pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}; | |||
| 28 | pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; | 40 | pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; |
| 29 | #[cfg(feature = "udp")] | 41 | #[cfg(feature = "udp")] |
| 30 | pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint}; | 42 | pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint}; |
| 43 | |||
| 44 | use crate::device::{Device, DeviceAdapter, LinkState}; | ||
| 45 | |||
| 46 | const LOCAL_PORT_MIN: u16 = 1025; | ||
| 47 | const LOCAL_PORT_MAX: u16 = 65535; | ||
| 48 | |||
| 49 | pub struct StackResources<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> { | ||
| 50 | addresses: [IpCidr; ADDR], | ||
| 51 | sockets: [SocketStorage<'static>; SOCK], | ||
| 52 | |||
| 53 | #[cfg(feature = "medium-ethernet")] | ||
| 54 | routes: [Option<(IpCidr, Route)>; 1], | ||
| 55 | #[cfg(feature = "medium-ethernet")] | ||
| 56 | neighbor_cache: [Option<(IpAddress, Neighbor)>; NEIGHBOR], | ||
| 57 | } | ||
| 58 | |||
| 59 | impl<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> StackResources<ADDR, SOCK, NEIGHBOR> { | ||
| 60 | pub fn new() -> Self { | ||
| 61 | Self { | ||
| 62 | addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32); ADDR], | ||
| 63 | sockets: [SocketStorage::EMPTY; SOCK], | ||
| 64 | #[cfg(feature = "medium-ethernet")] | ||
| 65 | routes: [None; 1], | ||
| 66 | #[cfg(feature = "medium-ethernet")] | ||
| 67 | neighbor_cache: [None; NEIGHBOR], | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 73 | pub struct Config { | ||
| 74 | pub address: Ipv4Cidr, | ||
| 75 | pub gateway: Option<Ipv4Address>, | ||
| 76 | pub dns_servers: Vec<Ipv4Address, 3>, | ||
| 77 | } | ||
| 78 | |||
| 79 | pub enum ConfigStrategy { | ||
| 80 | Static(Config), | ||
| 81 | #[cfg(feature = "dhcpv4")] | ||
| 82 | Dhcp, | ||
| 83 | } | ||
| 84 | |||
| 85 | pub struct Stack<D: Device> { | ||
| 86 | pub(crate) socket: RefCell<SocketStack>, | ||
| 87 | inner: RefCell<Inner<D>>, | ||
| 88 | } | ||
| 89 | |||
| 90 | struct Inner<D: Device> { | ||
| 91 | device: D, | ||
| 92 | link_up: bool, | ||
| 93 | config: Option<Config>, | ||
| 94 | #[cfg(feature = "dhcpv4")] | ||
| 95 | dhcp_socket: Option<SocketHandle>, | ||
| 96 | } | ||
| 97 | |||
| 98 | pub(crate) struct SocketStack { | ||
| 99 | pub(crate) sockets: SocketSet<'static>, | ||
| 100 | pub(crate) iface: Interface<'static>, | ||
| 101 | pub(crate) waker: WakerRegistration, | ||
| 102 | next_local_port: u16, | ||
| 103 | } | ||
| 104 | |||
| 105 | impl<D: Device + 'static> Stack<D> { | ||
| 106 | pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>( | ||
| 107 | mut device: D, | ||
| 108 | config: ConfigStrategy, | ||
| 109 | resources: &'static mut StackResources<ADDR, SOCK, NEIGH>, | ||
| 110 | random_seed: u64, | ||
| 111 | ) -> Self { | ||
| 112 | #[cfg(feature = "medium-ethernet")] | ||
| 113 | let medium = device.capabilities().medium; | ||
| 114 | |||
| 115 | #[cfg(feature = "medium-ethernet")] | ||
| 116 | let ethernet_addr = if medium == Medium::Ethernet { | ||
| 117 | device.ethernet_address() | ||
| 118 | } else { | ||
| 119 | [0, 0, 0, 0, 0, 0] | ||
| 120 | }; | ||
| 121 | |||
| 122 | let mut b = InterfaceBuilder::new(); | ||
| 123 | b = b.ip_addrs(&mut resources.addresses[..]); | ||
| 124 | b = b.random_seed(random_seed); | ||
| 125 | |||
| 126 | #[cfg(feature = "medium-ethernet")] | ||
| 127 | if medium == Medium::Ethernet { | ||
| 128 | b = b.hardware_addr(HardwareAddress::Ethernet(EthernetAddress(ethernet_addr))); | ||
| 129 | b = b.neighbor_cache(NeighborCache::new(&mut resources.neighbor_cache[..])); | ||
| 130 | b = b.routes(Routes::new(&mut resources.routes[..])); | ||
| 131 | } | ||
| 132 | |||
| 133 | let iface = b.finalize(&mut DeviceAdapter { | ||
| 134 | inner: &mut device, | ||
| 135 | cx: None, | ||
| 136 | }); | ||
| 137 | |||
| 138 | let sockets = SocketSet::new(&mut resources.sockets[..]); | ||
| 139 | |||
| 140 | let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; | ||
| 141 | |||
| 142 | let mut inner = Inner { | ||
| 143 | device, | ||
| 144 | link_up: false, | ||
| 145 | config: None, | ||
| 146 | #[cfg(feature = "dhcpv4")] | ||
| 147 | dhcp_socket: None, | ||
| 148 | }; | ||
| 149 | let mut socket = SocketStack { | ||
| 150 | sockets, | ||
| 151 | iface, | ||
| 152 | waker: WakerRegistration::new(), | ||
| 153 | next_local_port, | ||
| 154 | }; | ||
| 155 | |||
| 156 | match config { | ||
| 157 | ConfigStrategy::Static(config) => inner.apply_config(&mut socket, config), | ||
| 158 | #[cfg(feature = "dhcpv4")] | ||
| 159 | ConfigStrategy::Dhcp => { | ||
| 160 | let handle = socket.sockets.add(smoltcp::socket::dhcpv4::Socket::new()); | ||
| 161 | inner.dhcp_socket = Some(handle); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | Self { | ||
| 166 | socket: RefCell::new(socket), | ||
| 167 | inner: RefCell::new(inner), | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R { | ||
| 172 | f(&*self.socket.borrow(), &*self.inner.borrow()) | ||
| 173 | } | ||
| 174 | |||
| 175 | fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R { | ||
| 176 | f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut()) | ||
| 177 | } | ||
| 178 | |||
| 179 | pub fn ethernet_address(&self) -> [u8; 6] { | ||
| 180 | self.with(|_s, i| i.device.ethernet_address()) | ||
| 181 | } | ||
| 182 | |||
| 183 | pub fn is_link_up(&self) -> bool { | ||
| 184 | self.with(|_s, i| i.link_up) | ||
| 185 | } | ||
| 186 | |||
| 187 | pub fn is_config_up(&self) -> bool { | ||
| 188 | self.with(|_s, i| i.config.is_some()) | ||
| 189 | } | ||
| 190 | |||
| 191 | pub fn config(&self) -> Option<Config> { | ||
| 192 | self.with(|_s, i| i.config.clone()) | ||
| 193 | } | ||
| 194 | |||
| 195 | pub async fn run(&self) -> ! { | ||
| 196 | poll_fn(|cx| { | ||
| 197 | self.with_mut(|s, i| i.poll(cx, s)); | ||
| 198 | Poll::<()>::Pending | ||
| 199 | }) | ||
| 200 | .await; | ||
| 201 | unreachable!() | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | impl SocketStack { | ||
| 206 | #[allow(clippy::absurd_extreme_comparisons)] | ||
| 207 | pub fn get_local_port(&mut self) -> u16 { | ||
| 208 | let res = self.next_local_port; | ||
| 209 | self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; | ||
| 210 | res | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | impl<D: Device + 'static> Inner<D> { | ||
| 215 | fn apply_config(&mut self, s: &mut SocketStack, config: Config) { | ||
| 216 | #[cfg(feature = "medium-ethernet")] | ||
| 217 | let medium = self.device.capabilities().medium; | ||
| 218 | |||
| 219 | debug!("Acquired IP configuration:"); | ||
| 220 | |||
| 221 | debug!(" IP address: {}", config.address); | ||
| 222 | self.set_ipv4_addr(s, config.address); | ||
| 223 | |||
| 224 | #[cfg(feature = "medium-ethernet")] | ||
| 225 | if medium == Medium::Ethernet { | ||
| 226 | if let Some(gateway) = config.gateway { | ||
| 227 | debug!(" Default gateway: {}", gateway); | ||
| 228 | s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); | ||
| 229 | } else { | ||
| 230 | debug!(" Default gateway: None"); | ||
| 231 | s.iface.routes_mut().remove_default_ipv4_route(); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | for (i, s) in config.dns_servers.iter().enumerate() { | ||
| 235 | debug!(" DNS server {}: {}", i, s); | ||
| 236 | } | ||
| 237 | |||
| 238 | self.config = Some(config) | ||
| 239 | } | ||
| 240 | |||
| 241 | #[allow(unused)] // used only with dhcp | ||
| 242 | fn unapply_config(&mut self, s: &mut SocketStack) { | ||
| 243 | #[cfg(feature = "medium-ethernet")] | ||
| 244 | let medium = self.device.capabilities().medium; | ||
| 245 | |||
| 246 | debug!("Lost IP configuration"); | ||
| 247 | self.set_ipv4_addr(s, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0)); | ||
| 248 | #[cfg(feature = "medium-ethernet")] | ||
| 249 | if medium == Medium::Ethernet { | ||
| 250 | s.iface.routes_mut().remove_default_ipv4_route(); | ||
| 251 | } | ||
| 252 | self.config = None | ||
| 253 | } | ||
| 254 | |||
| 255 | fn set_ipv4_addr(&mut self, s: &mut SocketStack, cidr: Ipv4Cidr) { | ||
| 256 | s.iface.update_ip_addrs(|addrs| { | ||
| 257 | let dest = addrs.iter_mut().next().unwrap(); | ||
| 258 | *dest = IpCidr::Ipv4(cidr); | ||
| 259 | }); | ||
| 260 | } | ||
| 261 | |||
| 262 | fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { | ||
| 263 | s.waker.register(cx.waker()); | ||
| 264 | |||
| 265 | let timestamp = instant_to_smoltcp(Instant::now()); | ||
| 266 | let mut smoldev = DeviceAdapter { | ||
| 267 | cx: Some(cx), | ||
| 268 | inner: &mut self.device, | ||
| 269 | }; | ||
| 270 | if s.iface.poll(timestamp, &mut smoldev, &mut s.sockets).is_err() { | ||
| 271 | // If poll() returns error, it may not be done yet, so poll again later. | ||
| 272 | cx.waker().wake_by_ref(); | ||
| 273 | return; | ||
| 274 | } | ||
| 275 | |||
| 276 | // Update link up | ||
| 277 | let old_link_up = self.link_up; | ||
| 278 | self.link_up = self.device.link_state(cx) == LinkState::Up; | ||
| 279 | |||
| 280 | // Print when changed | ||
| 281 | if old_link_up != self.link_up { | ||
| 282 | info!("link_up = {:?}", self.link_up); | ||
| 283 | } | ||
| 284 | |||
| 285 | #[cfg(feature = "dhcpv4")] | ||
| 286 | if let Some(dhcp_handle) = self.dhcp_socket { | ||
| 287 | let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle); | ||
| 288 | |||
| 289 | if self.link_up { | ||
| 290 | match socket.poll() { | ||
| 291 | None => {} | ||
| 292 | Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), | ||
| 293 | Some(dhcpv4::Event::Configured(config)) => { | ||
| 294 | let config = Config { | ||
| 295 | address: config.address, | ||
| 296 | gateway: config.router, | ||
| 297 | dns_servers: config.dns_servers, | ||
| 298 | }; | ||
| 299 | self.apply_config(s, config) | ||
| 300 | } | ||
| 301 | } | ||
| 302 | } else if old_link_up { | ||
| 303 | socket.reset(); | ||
| 304 | self.unapply_config(s); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | //if old_link_up || self.link_up { | ||
| 308 | // self.poll_configurator(timestamp) | ||
| 309 | //} | ||
| 310 | |||
| 311 | if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { | ||
| 312 | let t = Timer::at(instant_from_smoltcp(poll_at)); | ||
| 313 | pin_mut!(t); | ||
| 314 | if t.poll(cx).is_ready() { | ||
| 315 | cx.waker().wake_by_ref(); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | fn instant_to_smoltcp(instant: Instant) -> SmolInstant { | ||
| 322 | SmolInstant::from_millis(instant.as_millis() as i64) | ||
| 323 | } | ||
| 324 | |||
| 325 | fn instant_from_smoltcp(instant: SmolInstant) -> Instant { | ||
| 326 | Instant::from_millis(instant.total_millis() as u64) | ||
| 327 | } | ||
diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs deleted file mode 100644 index 21316e485..000000000 --- a/embassy-net/src/stack.rs +++ /dev/null | |||
| @@ -1,306 +0,0 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 2 | use core::future::{poll_fn, Future}; | ||
| 3 | use core::task::{Context, Poll}; | ||
| 4 | |||
| 5 | use embassy_sync::waitqueue::WakerRegistration; | ||
| 6 | use embassy_time::{Instant, Timer}; | ||
| 7 | use futures::pin_mut; | ||
| 8 | use heapless::Vec; | ||
| 9 | #[cfg(feature = "dhcpv4")] | ||
| 10 | use smoltcp::iface::SocketHandle; | ||
| 11 | use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage}; | ||
| 12 | #[cfg(feature = "medium-ethernet")] | ||
| 13 | use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes}; | ||
| 14 | #[cfg(feature = "medium-ethernet")] | ||
| 15 | use smoltcp::phy::Medium; | ||
| 16 | #[cfg(feature = "dhcpv4")] | ||
| 17 | use smoltcp::socket::dhcpv4; | ||
| 18 | use smoltcp::time::Instant as SmolInstant; | ||
| 19 | #[cfg(feature = "medium-ethernet")] | ||
| 20 | use smoltcp::wire::{EthernetAddress, HardwareAddress, IpAddress}; | ||
| 21 | use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr}; | ||
| 22 | |||
| 23 | use crate::device::{Device, DeviceAdapter, LinkState}; | ||
| 24 | |||
| 25 | const LOCAL_PORT_MIN: u16 = 1025; | ||
| 26 | const LOCAL_PORT_MAX: u16 = 65535; | ||
| 27 | |||
| 28 | pub struct StackResources<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> { | ||
| 29 | addresses: [IpCidr; ADDR], | ||
| 30 | sockets: [SocketStorage<'static>; SOCK], | ||
| 31 | |||
| 32 | #[cfg(feature = "medium-ethernet")] | ||
| 33 | routes: [Option<(IpCidr, Route)>; 1], | ||
| 34 | #[cfg(feature = "medium-ethernet")] | ||
| 35 | neighbor_cache: [Option<(IpAddress, Neighbor)>; NEIGHBOR], | ||
| 36 | } | ||
| 37 | |||
| 38 | impl<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> StackResources<ADDR, SOCK, NEIGHBOR> { | ||
| 39 | pub fn new() -> Self { | ||
| 40 | Self { | ||
| 41 | addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32); ADDR], | ||
| 42 | sockets: [SocketStorage::EMPTY; SOCK], | ||
| 43 | #[cfg(feature = "medium-ethernet")] | ||
| 44 | routes: [None; 1], | ||
| 45 | #[cfg(feature = "medium-ethernet")] | ||
| 46 | neighbor_cache: [None; NEIGHBOR], | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 52 | pub struct Config { | ||
| 53 | pub address: Ipv4Cidr, | ||
| 54 | pub gateway: Option<Ipv4Address>, | ||
| 55 | pub dns_servers: Vec<Ipv4Address, 3>, | ||
| 56 | } | ||
| 57 | |||
| 58 | pub enum ConfigStrategy { | ||
| 59 | Static(Config), | ||
| 60 | #[cfg(feature = "dhcpv4")] | ||
| 61 | Dhcp, | ||
| 62 | } | ||
| 63 | |||
| 64 | pub struct Stack<D: Device> { | ||
| 65 | pub(crate) socket: RefCell<SocketStack>, | ||
| 66 | inner: RefCell<Inner<D>>, | ||
| 67 | } | ||
| 68 | |||
| 69 | struct Inner<D: Device> { | ||
| 70 | device: D, | ||
| 71 | link_up: bool, | ||
| 72 | config: Option<Config>, | ||
| 73 | #[cfg(feature = "dhcpv4")] | ||
| 74 | dhcp_socket: Option<SocketHandle>, | ||
| 75 | } | ||
| 76 | |||
| 77 | pub(crate) struct SocketStack { | ||
| 78 | pub(crate) sockets: SocketSet<'static>, | ||
| 79 | pub(crate) iface: Interface<'static>, | ||
| 80 | pub(crate) waker: WakerRegistration, | ||
| 81 | next_local_port: u16, | ||
| 82 | } | ||
| 83 | |||
| 84 | impl<D: Device + 'static> Stack<D> { | ||
| 85 | pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>( | ||
| 86 | mut device: D, | ||
| 87 | config: ConfigStrategy, | ||
| 88 | resources: &'static mut StackResources<ADDR, SOCK, NEIGH>, | ||
| 89 | random_seed: u64, | ||
| 90 | ) -> Self { | ||
| 91 | #[cfg(feature = "medium-ethernet")] | ||
| 92 | let medium = device.capabilities().medium; | ||
| 93 | |||
| 94 | #[cfg(feature = "medium-ethernet")] | ||
| 95 | let ethernet_addr = if medium == Medium::Ethernet { | ||
| 96 | device.ethernet_address() | ||
| 97 | } else { | ||
| 98 | [0, 0, 0, 0, 0, 0] | ||
| 99 | }; | ||
| 100 | |||
| 101 | let mut b = InterfaceBuilder::new(); | ||
| 102 | b = b.ip_addrs(&mut resources.addresses[..]); | ||
| 103 | b = b.random_seed(random_seed); | ||
| 104 | |||
| 105 | #[cfg(feature = "medium-ethernet")] | ||
| 106 | if medium == Medium::Ethernet { | ||
| 107 | b = b.hardware_addr(HardwareAddress::Ethernet(EthernetAddress(ethernet_addr))); | ||
| 108 | b = b.neighbor_cache(NeighborCache::new(&mut resources.neighbor_cache[..])); | ||
| 109 | b = b.routes(Routes::new(&mut resources.routes[..])); | ||
| 110 | } | ||
| 111 | |||
| 112 | let iface = b.finalize(&mut DeviceAdapter { | ||
| 113 | inner: &mut device, | ||
| 114 | cx: None, | ||
| 115 | }); | ||
| 116 | |||
| 117 | let sockets = SocketSet::new(&mut resources.sockets[..]); | ||
| 118 | |||
| 119 | let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; | ||
| 120 | |||
| 121 | let mut inner = Inner { | ||
| 122 | device, | ||
| 123 | link_up: false, | ||
| 124 | config: None, | ||
| 125 | #[cfg(feature = "dhcpv4")] | ||
| 126 | dhcp_socket: None, | ||
| 127 | }; | ||
| 128 | let mut socket = SocketStack { | ||
| 129 | sockets, | ||
| 130 | iface, | ||
| 131 | waker: WakerRegistration::new(), | ||
| 132 | next_local_port, | ||
| 133 | }; | ||
| 134 | |||
| 135 | match config { | ||
| 136 | ConfigStrategy::Static(config) => inner.apply_config(&mut socket, config), | ||
| 137 | #[cfg(feature = "dhcpv4")] | ||
| 138 | ConfigStrategy::Dhcp => { | ||
| 139 | let handle = socket.sockets.add(smoltcp::socket::dhcpv4::Socket::new()); | ||
| 140 | inner.dhcp_socket = Some(handle); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | Self { | ||
| 145 | socket: RefCell::new(socket), | ||
| 146 | inner: RefCell::new(inner), | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R { | ||
| 151 | f(&*self.socket.borrow(), &*self.inner.borrow()) | ||
| 152 | } | ||
| 153 | |||
| 154 | fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R { | ||
| 155 | f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut()) | ||
| 156 | } | ||
| 157 | |||
| 158 | pub fn ethernet_address(&self) -> [u8; 6] { | ||
| 159 | self.with(|_s, i| i.device.ethernet_address()) | ||
| 160 | } | ||
| 161 | |||
| 162 | pub fn is_link_up(&self) -> bool { | ||
| 163 | self.with(|_s, i| i.link_up) | ||
| 164 | } | ||
| 165 | |||
| 166 | pub fn is_config_up(&self) -> bool { | ||
| 167 | self.with(|_s, i| i.config.is_some()) | ||
| 168 | } | ||
| 169 | |||
| 170 | pub fn config(&self) -> Option<Config> { | ||
| 171 | self.with(|_s, i| i.config.clone()) | ||
| 172 | } | ||
| 173 | |||
| 174 | pub async fn run(&self) -> ! { | ||
| 175 | poll_fn(|cx| { | ||
| 176 | self.with_mut(|s, i| i.poll(cx, s)); | ||
| 177 | Poll::<()>::Pending | ||
| 178 | }) | ||
| 179 | .await; | ||
| 180 | unreachable!() | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | impl SocketStack { | ||
| 185 | #[allow(clippy::absurd_extreme_comparisons)] | ||
| 186 | pub fn get_local_port(&mut self) -> u16 { | ||
| 187 | let res = self.next_local_port; | ||
| 188 | self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; | ||
| 189 | res | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | impl<D: Device + 'static> Inner<D> { | ||
| 194 | fn apply_config(&mut self, s: &mut SocketStack, config: Config) { | ||
| 195 | #[cfg(feature = "medium-ethernet")] | ||
| 196 | let medium = self.device.capabilities().medium; | ||
| 197 | |||
| 198 | debug!("Acquired IP configuration:"); | ||
| 199 | |||
| 200 | debug!(" IP address: {}", config.address); | ||
| 201 | self.set_ipv4_addr(s, config.address); | ||
| 202 | |||
| 203 | #[cfg(feature = "medium-ethernet")] | ||
| 204 | if medium == Medium::Ethernet { | ||
| 205 | if let Some(gateway) = config.gateway { | ||
| 206 | debug!(" Default gateway: {}", gateway); | ||
| 207 | s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap(); | ||
| 208 | } else { | ||
| 209 | debug!(" Default gateway: None"); | ||
| 210 | s.iface.routes_mut().remove_default_ipv4_route(); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | for (i, s) in config.dns_servers.iter().enumerate() { | ||
| 214 | debug!(" DNS server {}: {}", i, s); | ||
| 215 | } | ||
| 216 | |||
| 217 | self.config = Some(config) | ||
| 218 | } | ||
| 219 | |||
| 220 | #[allow(unused)] // used only with dhcp | ||
| 221 | fn unapply_config(&mut self, s: &mut SocketStack) { | ||
| 222 | #[cfg(feature = "medium-ethernet")] | ||
| 223 | let medium = self.device.capabilities().medium; | ||
| 224 | |||
| 225 | debug!("Lost IP configuration"); | ||
| 226 | self.set_ipv4_addr(s, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0)); | ||
| 227 | #[cfg(feature = "medium-ethernet")] | ||
| 228 | if medium == Medium::Ethernet { | ||
| 229 | s.iface.routes_mut().remove_default_ipv4_route(); | ||
| 230 | } | ||
| 231 | self.config = None | ||
| 232 | } | ||
| 233 | |||
| 234 | fn set_ipv4_addr(&mut self, s: &mut SocketStack, cidr: Ipv4Cidr) { | ||
| 235 | s.iface.update_ip_addrs(|addrs| { | ||
| 236 | let dest = addrs.iter_mut().next().unwrap(); | ||
| 237 | *dest = IpCidr::Ipv4(cidr); | ||
| 238 | }); | ||
| 239 | } | ||
| 240 | |||
| 241 | fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { | ||
| 242 | s.waker.register(cx.waker()); | ||
| 243 | |||
| 244 | let timestamp = instant_to_smoltcp(Instant::now()); | ||
| 245 | let mut smoldev = DeviceAdapter { | ||
| 246 | cx: Some(cx), | ||
| 247 | inner: &mut self.device, | ||
| 248 | }; | ||
| 249 | if s.iface.poll(timestamp, &mut smoldev, &mut s.sockets).is_err() { | ||
| 250 | // If poll() returns error, it may not be done yet, so poll again later. | ||
| 251 | cx.waker().wake_by_ref(); | ||
| 252 | return; | ||
| 253 | } | ||
| 254 | |||
| 255 | // Update link up | ||
| 256 | let old_link_up = self.link_up; | ||
| 257 | self.link_up = self.device.link_state(cx) == LinkState::Up; | ||
| 258 | |||
| 259 | // Print when changed | ||
| 260 | if old_link_up != self.link_up { | ||
| 261 | info!("link_up = {:?}", self.link_up); | ||
| 262 | } | ||
| 263 | |||
| 264 | #[cfg(feature = "dhcpv4")] | ||
| 265 | if let Some(dhcp_handle) = self.dhcp_socket { | ||
| 266 | let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle); | ||
| 267 | |||
| 268 | if self.link_up { | ||
| 269 | match socket.poll() { | ||
| 270 | None => {} | ||
| 271 | Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), | ||
| 272 | Some(dhcpv4::Event::Configured(config)) => { | ||
| 273 | let config = Config { | ||
| 274 | address: config.address, | ||
| 275 | gateway: config.router, | ||
| 276 | dns_servers: config.dns_servers, | ||
| 277 | }; | ||
| 278 | self.apply_config(s, config) | ||
| 279 | } | ||
| 280 | } | ||
| 281 | } else if old_link_up { | ||
| 282 | socket.reset(); | ||
| 283 | self.unapply_config(s); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | //if old_link_up || self.link_up { | ||
| 287 | // self.poll_configurator(timestamp) | ||
| 288 | //} | ||
| 289 | |||
| 290 | if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { | ||
| 291 | let t = Timer::at(instant_from_smoltcp(poll_at)); | ||
| 292 | pin_mut!(t); | ||
| 293 | if t.poll(cx).is_ready() { | ||
| 294 | cx.waker().wake_by_ref(); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | fn instant_to_smoltcp(instant: Instant) -> SmolInstant { | ||
| 301 | SmolInstant::from_millis(instant.as_millis() as i64) | ||
| 302 | } | ||
| 303 | |||
| 304 | fn instant_from_smoltcp(instant: SmolInstant) -> Instant { | ||
| 305 | Instant::from_millis(instant.total_millis() as u64) | ||
| 306 | } | ||
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 0ed4b81e2..0dc8da73a 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs | |||
| @@ -8,9 +8,8 @@ use smoltcp::socket::tcp; | |||
| 8 | use smoltcp::time::Duration; | 8 | use smoltcp::time::Duration; |
| 9 | use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; | 9 | use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; |
| 10 | 10 | ||
| 11 | use super::stack::Stack; | ||
| 12 | use crate::device::Device; | 11 | use crate::device::Device; |
| 13 | use crate::stack::SocketStack; | 12 | use crate::{SocketStack, Stack}; |
| 14 | 13 | ||
| 15 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | 14 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
| 16 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 15 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 4ddad77d4..2f5334df3 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs | |||
| @@ -7,8 +7,7 @@ use smoltcp::iface::{Interface, SocketHandle}; | |||
| 7 | use smoltcp::socket::udp::{self, PacketMetadata}; | 7 | use smoltcp::socket::udp::{self, PacketMetadata}; |
| 8 | use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; | 8 | use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; |
| 9 | 9 | ||
| 10 | use super::stack::SocketStack; | 10 | use crate::{Device, SocketStack, Stack}; |
| 11 | use crate::{Device, Stack}; | ||
| 12 | 11 | ||
| 13 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | 12 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
| 14 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 13 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
