Add smoltcp dhcp socket configuration

This commit is contained in:
Paweł Jan Czochański 2023-01-18 10:10:33 +01:00 committed by Dario Nieuwenhuis
parent 2eae12b7f1
commit 8f4fae9b36
10 changed files with 81 additions and 87 deletions

View File

@ -30,6 +30,8 @@ use smoltcp::iface::SocketHandle;
use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage}; use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage};
#[cfg(feature = "dhcpv4")] #[cfg(feature = "dhcpv4")]
use smoltcp::socket::dhcpv4; use smoltcp::socket::dhcpv4;
use smoltcp::socket::dhcpv4::RetryConfig;
use smoltcp::time::Duration;
// smoltcp reexports // smoltcp reexports
pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant}; pub use smoltcp::time::{Duration as SmolDuration, Instant as SmolInstant};
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
@ -45,31 +47,53 @@ use crate::device::DriverAdapter;
const LOCAL_PORT_MIN: u16 = 1025; const LOCAL_PORT_MIN: u16 = 1025;
const LOCAL_PORT_MAX: u16 = 65535; const LOCAL_PORT_MAX: u16 = 65535;
pub struct StackResources<const SOCK: usize, const NEIGHBOR: usize> { pub struct StackResources<const SOCK: usize> {
addresses: [IpCidr; 5],
sockets: [SocketStorage<'static>; SOCK], sockets: [SocketStorage<'static>; SOCK],
} }
impl<const SOCK: usize, const NEIGHBOR: usize> StackResources<SOCK, NEIGHBOR> { impl<const SOCK: usize> StackResources<SOCK> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
addresses: [IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 32); 5],
sockets: [SocketStorage::EMPTY; SOCK], sockets: [SocketStorage::EMPTY; SOCK],
} }
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Config { pub struct StaticConfig {
pub address: Ipv4Cidr, pub address: Ipv4Cidr,
pub gateway: Option<Ipv4Address>, pub gateway: Option<Ipv4Address>,
pub dns_servers: Vec<Ipv4Address, 3>, pub dns_servers: Vec<Ipv4Address, 3>,
} }
pub enum ConfigStrategy { #[derive(Debug, Clone, PartialEq, Eq)]
Static(Config), pub struct DhcpConfig {
pub max_lease_duration: Option<Duration>,
pub retry_config: RetryConfig,
/// Ignore NAKs.
pub ignore_naks: bool,
/// Server port config
pub server_port: u16,
/// Client port config
pub client_port: u16,
}
impl Default for DhcpConfig {
fn default() -> Self {
Self {
max_lease_duration: Default::default(),
retry_config: Default::default(),
ignore_naks: Default::default(),
server_port: smoltcp::wire::DHCP_SERVER_PORT,
client_port: smoltcp::wire::DHCP_CLIENT_PORT,
}
}
}
pub enum Config {
Static(StaticConfig),
#[cfg(feature = "dhcpv4")] #[cfg(feature = "dhcpv4")]
Dhcp, Dhcp(DhcpConfig),
} }
pub struct Stack<D: Driver> { pub struct Stack<D: Driver> {
@ -80,7 +104,7 @@ pub struct Stack<D: Driver> {
struct Inner<D: Driver> { struct Inner<D: Driver> {
device: D, device: D,
link_up: bool, link_up: bool,
config: Option<Config>, config: Option<StaticConfig>,
#[cfg(feature = "dhcpv4")] #[cfg(feature = "dhcpv4")]
dhcp_socket: Option<SocketHandle>, dhcp_socket: Option<SocketHandle>,
} }
@ -93,17 +117,16 @@ pub(crate) struct SocketStack {
} }
impl<D: Driver + 'static> Stack<D> { impl<D: Driver + 'static> Stack<D> {
pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>( pub fn new<const SOCK: usize>(
mut device: D, mut device: D,
config: ConfigStrategy, config: Config,
resources: &'static mut StackResources<SOCK, NEIGH>, resources: &'static mut StackResources<SOCK>,
random_seed: u64, random_seed: u64,
) -> Self { ) -> Self {
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
let medium = device.capabilities().medium; let medium = device.capabilities().medium;
let mut b = InterfaceBuilder::new(); let mut b = InterfaceBuilder::new();
b = b.ip_addrs(Vec::<IpCidr, 5>::from_iter(resources.addresses));
b = b.random_seed(random_seed); b = b.random_seed(random_seed);
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
@ -136,10 +159,12 @@ impl<D: Driver + 'static> Stack<D> {
}; };
match config { match config {
ConfigStrategy::Static(config) => inner.apply_config(&mut socket, config), Config::Static(config) => inner.apply_config(&mut socket, config),
#[cfg(feature = "dhcpv4")] #[cfg(feature = "dhcpv4")]
ConfigStrategy::Dhcp => { Config::Dhcp(config) => {
let handle = socket.sockets.add(smoltcp::socket::dhcpv4::Socket::new()); let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new();
inner.apply_dhcp_config(&mut dhcp_socket, config);
let handle = socket.sockets.add(dhcp_socket);
inner.dhcp_socket = Some(handle); inner.dhcp_socket = Some(handle);
} }
} }
@ -170,7 +195,7 @@ impl<D: Driver + 'static> Stack<D> {
self.with(|_s, i| i.config.is_some()) self.with(|_s, i| i.config.is_some())
} }
pub fn config(&self) -> Option<Config> { pub fn config(&self) -> Option<StaticConfig> {
self.with(|_s, i| i.config.clone()) self.with(|_s, i| i.config.clone())
} }
@ -185,7 +210,7 @@ impl<D: Driver + 'static> Stack<D> {
} }
impl SocketStack { impl SocketStack {
#[allow(clippy::absurd_extreme_comparisons)] #[allow(clippy::absurd_extreme_comparisons, dead_code)]
pub fn get_local_port(&mut self) -> u16 { pub fn get_local_port(&mut self) -> u16 {
let res = self.next_local_port; let res = self.next_local_port;
self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 };
@ -194,7 +219,7 @@ impl SocketStack {
} }
impl<D: Driver + 'static> Inner<D> { impl<D: Driver + 'static> Inner<D> {
fn apply_config(&mut self, s: &mut SocketStack, config: Config) { fn apply_config(&mut self, s: &mut SocketStack, config: StaticConfig) {
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
let medium = self.device.capabilities().medium; let medium = self.device.capabilities().medium;
@ -220,6 +245,13 @@ impl<D: Driver + 'static> Inner<D> {
self.config = Some(config) self.config = Some(config)
} }
fn apply_dhcp_config(&self, socket: &mut smoltcp::socket::dhcpv4::Socket, config: DhcpConfig) {
socket.set_ignore_naks(config.ignore_naks);
socket.set_max_lease_duration(config.max_lease_duration);
socket.set_ports(config.server_port, config.client_port);
socket.set_retry_config(config.retry_config);
}
#[allow(unused)] // used only with dhcp #[allow(unused)] // used only with dhcp
fn unapply_config(&mut self, s: &mut SocketStack) { fn unapply_config(&mut self, s: &mut SocketStack) {
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
@ -280,7 +312,7 @@ impl<D: Driver + 'static> Inner<D> {
None => {} None => {}
Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
Some(dhcpv4::Event::Configured(config)) => { Some(dhcpv4::Event::Configured(config)) => {
let config = Config { let config = StaticConfig {
address: config.address, address: config.address,
gateway: config.router, gateway: config.router,
dns_servers: config.dns_servers, dns_servers: config.dns_servers,

View File

@ -101,8 +101,8 @@ async fn main(spawner: Spawner) {
let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
unwrap!(spawner.spawn(usb_ncm_task(runner))); unwrap!(spawner.spawn(usb_ncm_task(runner)));
let config = embassy_net::ConfigStrategy::Dhcp; let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(), // dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)), // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@ -115,12 +115,7 @@ async fn main(spawner: Spawner) {
let seed = u64::from_le_bytes(seed); let seed = u64::from_le_bytes(seed);
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
unwrap!(spawner.spawn(net_task(stack))); unwrap!(spawner.spawn(net_task(stack)));

View File

@ -92,8 +92,8 @@ async fn main(spawner: Spawner) {
let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
unwrap!(spawner.spawn(usb_ncm_task(runner))); unwrap!(spawner.spawn(usb_ncm_task(runner)));
let config = embassy_net::ConfigStrategy::Dhcp; let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(), // dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)), // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@ -103,12 +103,7 @@ async fn main(spawner: Spawner) {
let seed = 1234; // guaranteed random, chosen by a fair dice roll let seed = 1234; // guaranteed random, chosen by a fair dice roll
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
unwrap!(spawner.spawn(net_task(stack))); unwrap!(spawner.spawn(net_task(stack)));

View File

@ -17,7 +17,7 @@ async-io = "1.6.0"
env_logger = "0.9.0" env_logger = "0.9.0"
futures = { version = "0.3.17" } futures = { version = "0.3.17" }
log = "0.4.14" log = "0.4.14"
nix = "0.22.1" nix = "0.26.2"
libc = "0.2.101" libc = "0.2.101"
clap = { version = "3.0.0-beta.5", features = ["derive"] } clap = { version = "3.0.0-beta.5", features = ["derive"] }
rand_core = { version = "0.6.3", features = ["std"] } rand_core = { version = "0.6.3", features = ["std"] }

View File

@ -1,9 +1,11 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use std::default::Default;
use clap::Parser; use clap::Parser;
use embassy_executor::{Executor, Spawner}; use embassy_executor::{Executor, Spawner};
use embassy_net::tcp::TcpSocket; use embassy_net::tcp::TcpSocket;
use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, Stack, StackResources}; use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
use embedded_io::asynch::Write; use embedded_io::asynch::Write;
use heapless::Vec; use heapless::Vec;
use log::*; use log::*;
@ -48,13 +50,13 @@ async fn main_task(spawner: Spawner) {
// Choose between dhcp or static ip // Choose between dhcp or static ip
let config = if opts.static_ip { let config = if opts.static_ip {
ConfigStrategy::Static(embassy_net::Config { Config::Static(embassy_net::StaticConfig {
address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
dns_servers: Vec::new(), dns_servers: Vec::new(),
gateway: Some(Ipv4Address::new(192, 168, 69, 1)), gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
}) })
} else { } else {
ConfigStrategy::Dhcp Config::Dhcp(Default::default())
}; };
// Generate random seed // Generate random seed
@ -63,12 +65,7 @@ async fn main_task(spawner: Spawner) {
let seed = u64::from_le_bytes(seed); let seed = u64::from_le_bytes(seed);
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
// Launch network task // Launch network task
spawner.spawn(net_task(stack)).unwrap(); spawner.spawn(net_task(stack)).unwrap();

View File

@ -3,7 +3,7 @@
use clap::Parser; use clap::Parser;
use embassy_executor::{Executor, Spawner}; use embassy_executor::{Executor, Spawner};
use embassy_net::udp::UdpSocket; use embassy_net::udp::UdpSocket;
use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources}; use embassy_net::{Config, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources};
use heapless::Vec; use heapless::Vec;
use log::*; use log::*;
use rand_core::{OsRng, RngCore}; use rand_core::{OsRng, RngCore};
@ -47,13 +47,13 @@ async fn main_task(spawner: Spawner) {
// Choose between dhcp or static ip // Choose between dhcp or static ip
let config = if opts.static_ip { let config = if opts.static_ip {
ConfigStrategy::Static(embassy_net::Config { Config::Static(embassy_net::StaticConfig {
address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
dns_servers: Vec::new(), dns_servers: Vec::new(),
gateway: Some(Ipv4Address::new(192, 168, 69, 1)), gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
}) })
} else { } else {
ConfigStrategy::Dhcp Config::Dhcp(Default::default())
}; };
// Generate random seed // Generate random seed
@ -62,12 +62,7 @@ async fn main_task(spawner: Spawner) {
let seed = u64::from_le_bytes(seed); let seed = u64::from_le_bytes(seed);
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
// Launch network task // Launch network task
spawner.spawn(net_task(stack)).unwrap(); spawner.spawn(net_task(stack)).unwrap();

View File

@ -69,20 +69,15 @@ async fn main(spawner: Spawner) -> ! {
0, 0,
); );
let config = embassy_net::ConfigStrategy::Dhcp; let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(), // dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)), // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
//}); //});
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
// Launch network task // Launch network task
unwrap!(spawner.spawn(net_task(&stack))); unwrap!(spawner.spawn(net_task(&stack)));

View File

@ -70,20 +70,15 @@ async fn main(spawner: Spawner) -> ! {
0, 0,
); );
let config = embassy_net::ConfigStrategy::Dhcp; let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(), // dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)), // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
//}); //});
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
// Launch network task // Launch network task
unwrap!(spawner.spawn(net_task(&stack))); unwrap!(spawner.spawn(net_task(&stack)));

View File

@ -71,20 +71,15 @@ async fn main(spawner: Spawner) -> ! {
0, 0,
); );
let config = embassy_net::ConfigStrategy::Dhcp; let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { //let config = embassy_net::Config::StaticConfig(embassy_net::Config {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(), // dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)), // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
//}); //});
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
// Launch network task // Launch network task
unwrap!(spawner.spawn(net_task(&stack))); unwrap!(spawner.spawn(net_task(&stack)));

View File

@ -98,8 +98,8 @@ async fn main(spawner: Spawner) {
let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr); let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
unwrap!(spawner.spawn(usb_ncm_task(runner))); unwrap!(spawner.spawn(usb_ncm_task(runner)));
let config = embassy_net::ConfigStrategy::Dhcp; let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(), // dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)), // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@ -110,12 +110,7 @@ async fn main(spawner: Spawner) {
let seed = rng.next_u64(); let seed = rng.next_u64();
// Init network stack // Init network stack
let stack = &*singleton!(Stack::new( let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<1>::new()), seed));
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
unwrap!(spawner.spawn(net_task(stack))); unwrap!(spawner.spawn(net_task(stack)));