From dfb6c76f27814717eee138e8b086d245ab39e939 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 25 Jun 2023 23:37:50 +0800 Subject: [PATCH] Add static ip config Untested --- embassy/demos/common/src/config.rs | 59 ++++++++++++++++++-- embassy/demos/picow/src/main.rs | 3 + embassy/demos/picow/src/picowmenu.rs | 83 ++++++++++++++++++++++++---- embassy/demos/picow/src/w5500.rs | 8 ++- embassy/demos/picow/src/wifi.rs | 6 +- 5 files changed, 141 insertions(+), 18 deletions(-) diff --git a/embassy/demos/common/src/config.rs b/embassy/demos/common/src/config.rs index 1585ab9..829b488 100644 --- a/embassy/demos/common/src/config.rs +++ b/embassy/demos/common/src/config.rs @@ -12,7 +12,9 @@ use defmt::{debug, error, info, panic, trace, warn}; use hmac::{Hmac, Mac}; use sha2::Sha256; -use heapless::String; +use heapless::{String, Vec}; + +use embassy_net::{StaticConfigV4, Ipv4Cidr, Ipv4Address}; use sunset_sshwire_derive::*; @@ -51,7 +53,11 @@ pub struct SSHConfig { /// WPA2 passphrase. None is Open network. pub wifi_pw: Option>, + /// For wl5500. cyw43 uses its own internal pub mac: [u8; 6], + + /// `None` for DHCP + pub ip4_static: Option, } fn random_mac() -> Result<[u8; 6]> { @@ -62,15 +68,14 @@ fn random_mac() -> Result<[u8; 6]> { Ok(mac) } - impl SSHConfig { /// Bump this when the format changes - pub const CURRENT_VERSION: u8 = 5; + pub const CURRENT_VERSION: u8 = 6; /// A buffer this large will fit any SSHConfig. // It can be updated by looking at // `cargo test -- roundtrip_config` // in the demos/common directory - pub const BUF_SIZE: usize = 449; + pub const BUF_SIZE: usize = 460; /// Creates a new config with default parameters. /// @@ -91,6 +96,7 @@ impl SSHConfig { wifi_net, wifi_pw, mac, + ip4_static: None, }) } @@ -152,6 +158,38 @@ where bool::dec(s)?.then(|| SSHDecode::dec(s)).transpose() } +fn enc_ip4config(v: &Option, s: &mut dyn SSHSink) -> WireResult<()> { + v.is_some().enc(s)?; + if let Some(v) = v { + v.address.address().0.enc(s)?; + v.address.prefix_len().enc(s)?; + // to [u8; 4] + let gw = v.gateway.map(|a| a.0); + enc_option(&gw, s)?; + } + Ok(()) +} + +fn dec_ip4config<'de, S>(s: &mut S) -> WireResult> +where + S: SSHSource<'de>, +{ + let opt = bool::dec(s)?; + opt.then(|| { + let ad: [u8; 4] = SSHDecode::dec(s)?; + let ad = Ipv4Address::from_bytes(&ad); + let prefix = SSHDecode::dec(s)?; + let gw: Option<[u8; 4]> = dec_option(s)?; + let gateway = gw.map(|gw| Ipv4Address::from_bytes(&gw)); + Ok(StaticConfigV4 { + address: Ipv4Cidr::new(ad, prefix), + gateway, + dns_servers: Vec::new(), + }) + }) + .transpose() +} + impl SSHEncode for SSHConfig { fn enc(&self, s: &mut dyn SSHSink) -> WireResult<()> { info!("enc si"); @@ -176,6 +214,8 @@ impl SSHEncode for SSHConfig { self.mac.enc(s)?; + enc_ip4config(&self.ip4_static, s)?; + Ok(()) } } @@ -208,6 +248,8 @@ impl<'de> SSHDecode<'de> for SSHConfig { let mac = SSHDecode::dec(s)?; + let ip4_static = dec_ip4config(s)?; + Ok(Self { hostkey, console_pw, @@ -218,6 +260,7 @@ impl<'de> SSHDecode<'de> for SSHConfig { wifi_net, wifi_pw, mac, + ip4_static, }) } } @@ -320,7 +363,13 @@ mod tests { wifi_pw: Some( core::str::from_utf8([b'f'; 63].as_slice()).unwrap().into(), ), - mac: [6,2,3,4,5,6], + mac: [6, 2, 3, 4, 5, 6], + ip4_static: Some(embassy_net::StaticConfigV4 { + address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::UNSPECIFIED, 8), + gateway: Some(embassy_net::Ipv4Address::UNSPECIFIED), + // no dns servers. may need changing later? + dns_servers: heapless::Vec::new(), + }), }; // test once to determine size to print diff --git a/embassy/demos/picow/src/main.rs b/embassy/demos/picow/src/main.rs index 16d292a..47d64ea 100644 --- a/embassy/demos/picow/src/main.rs +++ b/embassy/demos/picow/src/main.rs @@ -49,6 +49,9 @@ mod wifi; #[cfg(not(any(feature = "cyw43", feature = "w5500")))] compile_error!("No network device selected. Use cyw43 or w5500 feature"); +#[cfg(all(feature = "cyw43", feature = "w5500"))] +compile_error!("Select only one of cyw43 or w5500"); + use demo_common::{SSHConfig, Shell}; use takepipe::TakePipe; diff --git a/embassy/demos/picow/src/picowmenu.rs b/embassy/demos/picow/src/picowmenu.rs index f54296a..58c5492 100644 --- a/embassy/demos/picow/src/picowmenu.rs +++ b/embassy/demos/picow/src/picowmenu.rs @@ -13,23 +13,25 @@ use core::fmt::Write; use core::future::{poll_fn, Future}; use core::ops::DerefMut; use core::sync::atomic::Ordering::{Relaxed, SeqCst}; +use core::str::FromStr; use embedded_io::{asynch, Io}; use embassy_sync::waitqueue::MultiWakerRegistration; use embassy_time::Duration; +use embassy_net::{Ipv4Cidr, Ipv4Address}; use heapless::{String, Vec}; -use crate::flashconfig; use crate::demo_common; +use crate::flashconfig; use crate::GlobalState; use demo_common::{BufOutput, SSHConfig}; use demo_common::menu::*; -use sunset::*; use sunset::packets::Ed25519PubKey; +use sunset::*; // arbitrary in bytes, for sizing buffers const MAX_PW_LEN: usize = 50; @@ -95,7 +97,10 @@ impl MenuCtx { let _ = writeln!(self.out, "serial can't loop"); } else { if self.state.usb_pipe.is_in_use() { - let _ = writeln!(self.out, "Opening usb1, stealing existing session"); + let _ = writeln!( + self.out, + "Opening usb1, stealing existing session" + ); } else { let _ = writeln!(self.out, "Opening usb1"); } @@ -111,7 +116,10 @@ impl MenuCtx { let _ = writeln!(self.out, "serial can't loop"); } else { if self.state.serial1_pipe.is_in_use() { - let _ = writeln!(self.out, "Opening serial1, stealing existing session"); + let _ = writeln!( + self.out, + "Opening serial1, stealing existing session" + ); } else { let _ = writeln!(self.out, "Opening serial1"); } @@ -404,6 +412,32 @@ const NET_ITEM: Item = Item { }, help: None, }, + &Item { + command: "dhcp", + item_type: ItemType::Callback { + parameters: &[], + function: do_net_dhcp, + }, + help: None, + }, + &Item { + command: "static", + item_type: ItemType::Callback { + parameters: &[ + Parameter::Mandatory { + parameter_name: "address/netmask", + help: None, + }, + Parameter::Optional { + parameter_name: "gateway", + help: None, + }, + ], + + function: do_net_static, + }, + help: None, + }, ], entry: None, exit: None, @@ -607,12 +641,10 @@ fn do_admin_clear_pw(_item: &Item, args: &[&str], context: &mut MenuCtx // fn do_gpio_set(_item: &Item, _args: &[&str], _context: &mut MenuCtx) {} fn do_erase_config(_item: &Item, _args: &[&str], context: &mut MenuCtx) { - context.with_config(|c, out| { - match SSHConfig::new() { - Ok(n) => *c = n, - Err(e) => { - let _ = writeln!(out, "failed: {e}"); - } + context.with_config(|c, out| match SSHConfig::new() { + Ok(n) => *c = n, + Err(e) => { + let _ = writeln!(out, "failed: {e}"); } }); context.need_save = true; @@ -633,7 +665,8 @@ fn do_bootsel(_item: &Item, _args: &[&str], context: &mut MenuCtx) { fn do_about(_item: &Item, _args: &[&str], context: &mut MenuCtx) { let _ = writeln!( context, - "Sunset SSH, USB serial\nMatt Johnston \n{}", env!("GIT_REV"), + "Sunset SSH, USB serial\nMatt Johnston \n{}", + env!("GIT_REV"), ); } @@ -696,6 +729,34 @@ fn do_net_info(_item: &Item, _args: &[&str], context: &mut MenuCtx) { }); } +fn do_net_dhcp(_item: &Item, _args: &[&str], context: &mut MenuCtx) { + context.with_config(|c, out| { + c.ip4_static = None; + }); +} + +fn do_net_static(_item: &Item, args: &[&str], context: &mut MenuCtx) { + context.with_config(|c, out| { + let ip = Ipv4Cidr::from_str(args[0]); + let gw = if args[1].is_empty() { + Ok(None) + } else { + Some(Ipv4Address::from_str(args[1])).transpose() + }; + match (ip, gw) { + (Ok(address), Ok(gateway)) => { + c.ip4_static = Some(embassy_net::StaticConfigV4 { + address, + gateway, + dns_servers: Vec::new(), + }) + } + _ => { + let _ = write!(out, "Bad args"); + } + } + }); +} // Returns an error on EOF etc. pub(crate) async fn request_pw( diff --git a/embassy/demos/picow/src/w5500.rs b/embassy/demos/picow/src/w5500.rs index dc9600d..324ebec 100644 --- a/embassy/demos/picow/src/w5500.rs +++ b/embassy/demos/picow/src/w5500.rs @@ -72,13 +72,19 @@ pub(crate) async fn w5500_stack( .await; spawner.spawn(ethernet_task(runner)).unwrap(); + let config = if let Some(ref s) = config.lock().await.ip4_static { + embassy_net::Config::ipv4_static(s.clone()) + } else { + embassy_net::Config::dhcpv4(Default::default()) + }; + // Generate random seed let seed = OsRng.next_u64(); // Init network stack let stack = &*make_static!(Stack::new( device, - embassy_net::Config::dhcpv4(Default::default()), + config, make_static!(StackResources::<{ crate::NUM_SOCKETS }>::new()), seed )); diff --git a/embassy/demos/picow/src/wifi.rs b/embassy/demos/picow/src/wifi.rs index 1a02d2e..a455ffd 100644 --- a/embassy/demos/picow/src/wifi.rs +++ b/embassy/demos/picow/src/wifi.rs @@ -86,7 +86,11 @@ pub(crate) async fn wifi_stack(spawner: &Spawner, } } - let config = embassy_net::Config::dhcpv4(Default::default()); + let config = if let Some(ref s) = config.lock().await.ip4_static { + embassy_net::Config::ipv4_static(s.clone()) + } else { + embassy_net::Config::dhcpv4(Default::default()) + }; let seed = OsRng.next_u64();