From bc5b74bd04f26bee3c3dfe15ae234be9d20fc72f Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 13 Jun 2023 23:41:59 +0800
Subject: [PATCH] Fix all the warnings for picow

---
 embassy/demos/common/src/config.rs     |   5 +-
 embassy/demos/common/src/server.rs     |   4 -
 embassy/demos/picow/Cargo.toml         |   4 +-
 embassy/demos/picow/src/flashconfig.rs |   6 +-
 embassy/demos/picow/src/main.rs        |  16 +--
 embassy/demos/picow/src/picowmenu.rs   | 170 +++++++++++++------------
 embassy/demos/picow/src/serial.rs      |   9 +-
 embassy/demos/picow/src/takepipe.rs    |   6 +-
 embassy/demos/picow/src/usbserial.rs   |   5 +-
 embassy/demos/picow/src/wifi.rs        |   5 +-
 embassy/src/embassy_sunset.rs          |  10 +-
 src/behaviour.rs                       |   4 +-
 src/channel.rs                         |   2 +-
 src/cliauth.rs                         |   9 +-
 src/client.rs                          |   4 -
 src/conn.rs                            |   6 +-
 src/kex.rs                             |  30 ++++-
 src/packets.rs                         |   2 +-
 src/sign.rs                            |   2 +-
 src/sshnames.rs                        |   1 +
 20 files changed, 152 insertions(+), 148 deletions(-)

diff --git a/embassy/demos/common/src/config.rs b/embassy/demos/common/src/config.rs
index 0406fa5..bda9add 100644
--- a/embassy/demos/common/src/config.rs
+++ b/embassy/demos/common/src/config.rs
@@ -12,13 +12,12 @@ use defmt::{debug, error, info, panic, trace, warn};
 use hmac::{Hmac, Mac};
 use sha2::Sha256;
 
-use heapless::{String, Vec};
+use heapless::String;
 
 use sunset_sshwire_derive::*;
 
-use sunset::sshwire;
 use sunset::sshwire::{
-    BinString, SSHDecode, SSHEncode, SSHSink, SSHSource, WireError, WireResult,
+    SSHDecode, SSHEncode, SSHSink, SSHSource, WireError, WireResult,
 };
 
 use sunset::packets::Ed25519PubKey;
diff --git a/embassy/demos/common/src/server.rs b/embassy/demos/common/src/server.rs
index 7f24db8..d6c9fe0 100644
--- a/embassy/demos/common/src/server.rs
+++ b/embassy/demos/common/src/server.rs
@@ -9,15 +9,11 @@ use {
 #[cfg(feature = "defmt")]
 use defmt::{debug, info, warn, panic, error, trace};
 
-use core::fmt::Write as _;
-use pretty_hex::PrettyHex;
-
 use embassy_sync::mutex::Mutex;
 use embassy_sync::blocking_mutex::raw::NoopRawMutex;
 use embassy_net::tcp::TcpSocket;
 use embassy_net::Stack;
 use embassy_net_driver::Driver;
-use embassy_futures::join::join;
 use embassy_futures::select::{select, Either};
 use embassy_time::{Duration, Timer};
 
diff --git a/embassy/demos/picow/Cargo.toml b/embassy/demos/picow/Cargo.toml
index b977705..4810e9b 100644
--- a/embassy/demos/picow/Cargo.toml
+++ b/embassy/demos/picow/Cargo.toml
@@ -60,7 +60,7 @@ rand = { version = "0.8", default-features = false, features = ["getrandom"] }
 sha2 = { version = "0.10", default-features = false }
 
 # for defmt feature
-smoltcp = { default-features = false }
+smoltcp = { version = "0.9", default-features = false }
 
 [features]
 default = ["defmt", "sunset-demo-embassy-common/defmt", "embassy-usb/defmt"]
@@ -71,7 +71,7 @@ defmt = ["dep:defmt", "sunset/defmt", "sunset-embassy/defmt", "smoltcp/defmt"]
 # probe-rs-cli download firmware/43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
 romfw = []
 
-# Add a UART on tx pin1, rx pin2
+# Default console is serial
 serial1 = []
 
 [patch.crates-io]
diff --git a/embassy/demos/picow/src/flashconfig.rs b/embassy/demos/picow/src/flashconfig.rs
index 7a82ef9..c32bbcd 100644
--- a/embassy/demos/picow/src/flashconfig.rs
+++ b/embassy/demos/picow/src/flashconfig.rs
@@ -12,7 +12,7 @@ pub use {
 #[cfg(feature = "defmt")]
 pub use defmt::{debug, info, warn, panic, error, trace};
 
-use embassy_rp::flash::{Flash, ERASE_SIZE, FLASH_BASE};
+use embassy_rp::flash::{Flash, ERASE_SIZE};
 use embassy_rp::peripherals::FLASH;
 
 use sha2::Digest;
@@ -21,7 +21,6 @@ use core::borrow::Borrow;
 
 use sunset_sshwire_derive::*;
 use sunset::sshwire;
-use sunset::sshwire::{BinString, SSHEncode, SSHDecode, WireResult, SSHSource, SSHSink, WireError};
 use sunset::sshwire::OwnOrBorrow;
 
 use crate::demo_common;
@@ -53,7 +52,6 @@ fn config_hash(config: &SSHConfig) -> Result<[u8; 32]> {
 /// Loads a SSHConfig at startup. Good for persisting hostkeys.
 pub fn load_or_create(flash: &mut Flash<'_, FLASH, FLASH_SIZE>) -> Result<SSHConfig> {
     use snafu::Error;
-    let c = load(flash);
     match load(flash) {
         Ok(c) => {
             info!("Good existing config");
@@ -68,7 +66,7 @@ pub fn load_or_create(flash: &mut Flash<'_, FLASH, FLASH_SIZE>) -> Result<SSHCon
 
 pub fn create(flash: &mut Flash<'_, FLASH, FLASH_SIZE>) -> Result<SSHConfig> {
     let c = SSHConfig::new()?;
-    if let Err(e) = save(flash, &c) {
+    if let Err(_) = save(flash, &c) {
         warn!("Error writing config");
     }
     Ok(c)
diff --git a/embassy/demos/picow/src/main.rs b/embassy/demos/picow/src/main.rs
index aa5bb94..55515b5 100644
--- a/embassy/demos/picow/src/main.rs
+++ b/embassy/demos/picow/src/main.rs
@@ -14,15 +14,10 @@ pub use defmt::{debug, error, info, panic, trace, warn};
 
 use {defmt_rtt as _, panic_probe as _};
 
-use core::fmt::Write as _;
-use pretty_hex::PrettyHex;
-
 use embassy_executor::Spawner;
-use embassy_futures::join::join;
 use embassy_futures::select::select;
 use embassy_net::Stack;
 use embassy_rp::peripherals::FLASH;
-use embassy_time::Duration;
 use embedded_io::asynch::Write as _;
 use embedded_io::{asynch, Io};
 
@@ -43,13 +38,12 @@ pub(crate) use sunset_demo_embassy_common as demo_common;
 
 mod flashconfig;
 mod picowmenu;
-#[cfg(feature = "serial1")]
 mod serial;
 mod takepipe;
 mod usbserial;
 mod wifi;
 
-use demo_common::{demo_menu, SSHConfig, Shell};
+use demo_common::{SSHConfig, Shell};
 
 use takepipe::TakePipe;
 
@@ -97,12 +91,10 @@ async fn main(spawner: Spawner) {
         singleton!(p.pipe())
     };
 
-    #[cfg(feature = "serial1")]
     let serial1_pipe = {
         let s = singleton!(takepipe::TakePipeStorage::new());
         singleton!(s.pipe())
     };
-    #[cfg(feature = "serial1")]
     spawner
         .spawn(serial::task(
             p.UART0,
@@ -120,10 +112,9 @@ async fn main(spawner: Spawner) {
 
     let state = GlobalState {
         usb_pipe,
-        #[cfg(feature = "serial1")]
         serial1_pipe,
 
-        wifi_control,
+        _wifi_control: wifi_control,
         config,
         flash,
         watchdog,
@@ -150,10 +141,9 @@ async fn listener(
 pub(crate) struct GlobalState {
     // If taking multiple mutexes, lock in the order below avoid inversion.
     pub usb_pipe: &'static TakePipe<'static>,
-    #[cfg(feature = "serial1")]
     pub serial1_pipe: &'static TakePipe<'static>,
 
-    pub wifi_control: &'static SunsetMutex<cyw43::Control<'static>>,
+    pub _wifi_control: &'static SunsetMutex<cyw43::Control<'static>>,
     pub config: &'static SunsetMutex<SSHConfig>,
     pub flash: &'static SunsetMutex<
         embassy_rp::flash::Flash<'static, FLASH, { flashconfig::FLASH_SIZE }>,
diff --git a/embassy/demos/picow/src/picowmenu.rs b/embassy/demos/picow/src/picowmenu.rs
index b610422..5ac58f0 100644
--- a/embassy/demos/picow/src/picowmenu.rs
+++ b/embassy/demos/picow/src/picowmenu.rs
@@ -1,3 +1,6 @@
+// callbacks have lots of unused arguments. Ignore them, this might get replaced.
+#![allow(unused)]
+
 #[allow(unused_imports)]
 #[cfg(not(feature = "defmt"))]
 pub use log::{debug, error, info, log, trace, warn};
@@ -12,7 +15,6 @@ use core::ops::DerefMut;
 use core::sync::atomic::Ordering::{Relaxed, SeqCst};
 
 use embedded_io::{asynch, Io};
-use embedded_io::asynch::Write as _;
 
 use embassy_sync::waitqueue::MultiWakerRegistration;
 use embassy_time::Duration;
@@ -69,7 +71,7 @@ impl MenuCtx {
         let mut c = match self.state.config.try_lock() {
             Ok(c) => c,
             Err(e) => {
-                writeln!(self, "Lock problem, try again.");
+                let _ = writeln!(self, "Lock problem, try again.");
                 return false;
             }
         };
@@ -90,12 +92,12 @@ impl MenuCtx {
         if self.switch_usb1 {
             self.switch_usb1 = false;
             if self.local {
-                writeln!(self.out, "serial can't loop");
+                let _ = writeln!(self.out, "serial can't loop");
             } else {
                 if self.state.usb_pipe.is_in_use() {
-                    writeln!(self.out, "Opening usb1, stealing existing session");
+                    let _ = writeln!(self.out, "Opening usb1, stealing existing session");
                 } else {
-                    writeln!(self.out, "Opening usb1");
+                    let _ = writeln!(self.out, "Opening usb1");
                 }
                 crate::serial(chanr, chanw, self.state.usb_pipe).await?;
                 // TODO we could return to the menu on serial error?
@@ -103,16 +105,15 @@ impl MenuCtx {
             }
         }
 
-        #[cfg(feature = "serial1")]
         if self.switch_serial1 {
             self.switch_serial1 = false;
             if self.local {
-                writeln!(self.out, "serial can't loop");
+                let _ = writeln!(self.out, "serial can't loop");
             } else {
                 if self.state.serial1_pipe.is_in_use() {
-                    writeln!(self.out, "Opening serial1, stealing existing session");
+                    let _ = writeln!(self.out, "Opening serial1, stealing existing session");
                 } else {
-                    writeln!(self.out, "Opening serial1");
+                    let _ = writeln!(self.out, "Opening serial1");
                 }
                 crate::serial(chanr, chanw, self.state.serial1_pipe).await?;
                 // TODO we could return to the menu on serial error?
@@ -170,7 +171,7 @@ pub(crate) const SETUP_MENU: Menu<MenuCtx> = Menu {
             item_type: ItemType::Callback { function: do_logout, parameters: &[] },
         },
         &AUTH_ITEM,
-        &GPIO_ITEM,
+        // &GPIO_ITEM,
         &SERIAL_ITEM,
         &WIFI_ITEM,
         &Item {
@@ -389,39 +390,39 @@ const WIFI_ITEM: Item<MenuCtx> = Item {
     help: None,
 };
 
-const GPIO_ITEM: Item<MenuCtx> = Item {
-    command: "gpio",
-    item_type: ItemType::Menu(&Menu {
-        label: "gpio",
-        items: &[
-            &Item {
-                command: "show",
-                item_type: ItemType::Callback {
-                    parameters: &[],
-                    function: do_gpio_show,
-                },
-                help: None,
-            },
-            &Item {
-                command: "set",
-                item_type: ItemType::Callback {
-                    parameters: &[
-                        Parameter::Mandatory { parameter_name: "pin", help: None },
-                        Parameter::Mandatory {
-                            parameter_name: "state",
-                            help: Some("0/1/Z"),
-                        },
-                    ],
-                    function: do_gpio_set,
-                },
-                help: None,
-            },
-        ],
-        entry: None,
-        exit: None,
-    }),
-    help: Some("GPIO, todo"),
-};
+// const _GPIO_ITEM: Item<MenuCtx> = Item {
+//     command: "gpio",
+//     item_type: ItemType::Menu(&Menu {
+//         label: "gpio",
+//         items: &[
+//             &Item {
+//                 command: "show",
+//                 item_type: ItemType::Callback {
+//                     parameters: &[],
+//                     function: do_gpio_show,
+//                 },
+//                 help: None,
+//             },
+//             &Item {
+//                 command: "set",
+//                 item_type: ItemType::Callback {
+//                     parameters: &[
+//                         Parameter::Mandatory { parameter_name: "pin", help: None },
+//                         Parameter::Mandatory {
+//                             parameter_name: "state",
+//                             help: Some("0/1/Z"),
+//                         },
+//                     ],
+//                     function: do_gpio_set,
+//                 },
+//                 help: None,
+//             },
+//         ],
+//         entry: None,
+//         exit: None,
+//     }),
+//     help: Some("GPIO, todo"),
+// };
 
 const SERIAL_ITEM: Item<MenuCtx> = Item {
     command: "serial",
@@ -433,7 +434,6 @@ const SERIAL_ITEM: Item<MenuCtx> = Item {
                 item_type: ItemType::Callback { parameters: &[], function: do_usb1 },
                 help: Some("Connect to if00 serial port. Disconnect to exit."),
             },
-            #[cfg(feature = "serial1")]
             &Item {
                 command: "serial1",
                 item_type: ItemType::Callback {
@@ -450,7 +450,7 @@ const SERIAL_ITEM: Item<MenuCtx> = Item {
 };
 
 fn enter_auth(context: &mut MenuCtx) {
-    writeln!(context, "In auth menu").unwrap();
+    let _ = writeln!(context, "In auth menu").unwrap();
 }
 
 fn endis(v: bool) -> &'static str {
@@ -463,25 +463,25 @@ fn endis(v: bool) -> &'static str {
 
 fn prkey(context: &mut dyn Write, name: &str, k: &Option<Ed25519PubKey>) {
     if let Some(k) = k {
-        writeln!(context, "{} ed25519 todo", name);
+        let _ = writeln!(context, "{} ed25519 todo", name);
     } else {
-        writeln!(context, "{} disabled", name);
+        let _ = writeln!(context, "{} disabled", name);
     }
 }
 
 fn do_auth_show(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
     context.with_config(|c, out| {
-        write!(out, "Console password ");
+        let _ = write!(out, "Console password ");
         if c.console_noauth {
-            writeln!(out, "not required");
+            let _ = writeln!(out, "not required");
         } else {
-            writeln!(out, "{}", endis(c.console_pw.is_some()));
+            let _ = writeln!(out, "{}", endis(c.console_pw.is_some()));
         }
-        writeln!(out, "Console password {}", endis(c.console_pw.is_some()));
+        let _ = writeln!(out, "Console password {}", endis(c.console_pw.is_some()));
         prkey(out, "Console key1", &c.console_keys[0]);
         prkey(out, "Console key2", &c.console_keys[1]);
         prkey(out, "Console key3", &c.console_keys[2]);
-        writeln!(out, "Admin password {}", endis(c.admin_pw.is_some()));
+        let _ = writeln!(out, "Admin password {}", endis(c.admin_pw.is_some()));
         prkey(out, "Admin key1", &c.admin_keys[0]);
         prkey(out, "Admin key2", &c.admin_keys[1]);
         prkey(out, "Admin key3", &c.admin_keys[2]);
@@ -491,33 +491,33 @@ fn do_auth_show(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
 fn do_key(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
     let slot: usize = match args[0].parse() {
         Err(e) => {
-            writeln!(context, "Bad slot");
+            let _ = writeln!(context, "Bad slot");
             return;
         }
         Ok(s) => s,
     };
     if slot == 0 || slot > demo_common::config::KEY_SLOTS {
-        writeln!(context, "Bad slot");
+        let _ = writeln!(context, "Bad slot");
         return;
     }
     context.need_save = true;
 
-    writeln!(context, "todo openssh key parsing");
+    let _ = writeln!(context, "todo openssh key parsing");
 }
 
 fn do_clear_key(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
-    writeln!(context, "todo");
+    let _ = writeln!(context, "todo");
     context.need_save = true;
 }
 
 fn do_console_pw(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
     let pw = args[0];
     if pw.as_bytes().len() > MAX_PW_LEN {
-        writeln!(context, "Too long");
+        let _ = writeln!(context, "Too long");
         return;
     }
     context.with_config(|c, out| {
-        match c.set_console_pw(Some(pw)) {
+        let _ = match c.set_console_pw(Some(pw)) {
             Ok(()) => writeln!(out, "Set console password"),
             Err(e) => writeln!(out, "Failed setting, {}", e),
         };
@@ -539,19 +539,19 @@ fn do_console_noauth(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx
 }
 
 fn do_admin_key(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
-    writeln!(context, "todo");
+    let _ = writeln!(context, "todo");
     context.need_save = true;
 }
 
 fn do_admin_clear_key(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
-    writeln!(context, "todo");
+    let _ = writeln!(context, "todo");
     context.need_save = true;
 }
 
 fn do_console_clear_pw(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
     context.with_config(|c, out| {
         let _ = c.set_console_pw(None);
-        writeln!(out, "Disabled console password");
+        let _ = writeln!(out, "Disabled console password");
     });
     context.need_save = true;
 }
@@ -559,11 +559,11 @@ fn do_console_clear_pw(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuC
 fn do_admin_pw(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
     let pw = args[0];
     if pw.as_bytes().len() > MAX_PW_LEN {
-        writeln!(context, "Too long");
+        let _ = writeln!(context, "Too long");
         return;
     }
     context.with_config(|c, out| {
-        match c.set_admin_pw(Some(pw)) {
+        let _ = match c.set_admin_pw(Some(pw)) {
             Ok(()) => writeln!(out, "Set admin password"),
             Err(e) => writeln!(out, "Failed setting, {}", e),
         };
@@ -574,28 +574,38 @@ fn do_admin_pw(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
 fn do_admin_clear_pw(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
     context.with_config(|c, out| {
         let _ = c.set_admin_pw(None);
-        writeln!(out, "Disabled admin password");
+        let _ = writeln!(out, "Disabled admin password");
     });
     context.need_save = true;
 }
 
-fn do_gpio_show(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
-    writeln!(context, "gpio show here");
-}
+// fn do_gpio_show(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
+//     let _ = writeln!(context, "gpio show here");
+// }
 
-fn do_gpio_set(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {}
+// fn do_gpio_set(_item: &Item<MenuCtx>, _args: &[&str], _context: &mut MenuCtx) {}
 
-fn do_erase_config(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {}
+fn do_erase_config(_item: &Item<MenuCtx>, _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.need_save = true;
+}
 
-fn do_logout(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
+fn do_logout(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
     context.logout = true;
 }
 
-fn do_reset(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
+fn do_reset(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
     context.reset = true;
 }
 
-fn do_bootsel(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
+fn do_bootsel(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
     context.bootsel = true;
 }
 
@@ -607,22 +617,22 @@ fn do_about(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
 }
 
 fn do_usb1(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
-    writeln!(context, "USB serial");
+    let _ = writeln!(context, "USB serial");
     context.switch_usb1 = true;
 }
 
 fn do_serial1(_item: &Item<MenuCtx>, _args: &[&str], context: &mut MenuCtx) {
-    writeln!(context, "serial1");
+    let _ = writeln!(context, "serial1");
     context.switch_serial1 = true;
 }
 
 fn wifi_entry(context: &mut MenuCtx) {
     context.with_config(|c, out| {
-        write!(out, "Wifi net {} ", c.wifi_net);
+        let _ = write!(out, "Wifi net {} ", c.wifi_net);
         if c.wifi_pw.is_some() {
-            writeln!(out, "wpa2");
+            let _ = writeln!(out, "wpa2");
         } else {
-            writeln!(out, "open");
+            let _ = writeln!(out, "open");
         }
     });
 }
@@ -632,11 +642,11 @@ fn do_wifi_wpa2(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
         let net = args[0];
         let pw = args[1];
         if c.wifi_net.capacity() < net.len() {
-            writeln!(out, "Too long net");
+            let _ = writeln!(out, "Too long net");
             return;
         }
         if pw.len() > 63 {
-            writeln!(out, "Too long pw");
+            let _ = writeln!(out, "Too long pw");
             return;
         }
         c.wifi_net = net.into();
@@ -650,7 +660,7 @@ fn do_wifi_open(_item: &Item<MenuCtx>, args: &[&str], context: &mut MenuCtx) {
     context.with_config(|c, out| {
         let net = args[0];
         if c.wifi_net.capacity() < net.len() {
-            writeln!(out, "Too long net");
+            let _ = writeln!(out, "Too long net");
             return;
         }
         c.wifi_pw = None;
diff --git a/embassy/demos/picow/src/serial.rs b/embassy/demos/picow/src/serial.rs
index 25e38e0..4258cad 100644
--- a/embassy/demos/picow/src/serial.rs
+++ b/embassy/demos/picow/src/serial.rs
@@ -9,16 +9,11 @@ pub use log::{debug, error, info, log, trace, warn};
 pub use defmt::{debug, error, info, panic, trace, warn};
 
 use embassy_rp::peripherals::*;
-use embassy_rp::interrupt::UART0_IRQ;
-use embassy_rp::{bind_interrupts, Peripheral};
+use embassy_rp::bind_interrupts;
 use embassy_rp::uart::{
-    self as rp_uart, BufferedInterruptHandler, BufferedUart, BufferedUartRx, CtsPin,
-    RtsPin, RxPin, TxPin,
+    self as rp_uart, BufferedInterruptHandler, BufferedUart, 
 };
 
-use embassy_rp::interrupt::{Interrupt, InterruptExt};
-
-use sunset::*;
 use sunset_embassy::*;
 
 use crate::*;
diff --git a/embassy/demos/picow/src/takepipe.rs b/embassy/demos/picow/src/takepipe.rs
index d14a94b..c5011ef 100644
--- a/embassy/demos/picow/src/takepipe.rs
+++ b/embassy/demos/picow/src/takepipe.rs
@@ -12,7 +12,7 @@ use core::ops::DerefMut;
 
 use embedded_io::{asynch, Io};
 
-use embassy_sync::{pipe, mutex::{MutexGuard, Mutex}, signal::Signal};
+use embassy_sync::{pipe, mutex::Mutex, signal::Signal};
 use embassy_sync::pipe::Pipe;
 use embassy_futures::select::{select, Either};
 
@@ -38,7 +38,6 @@ pub(crate) struct TakePipeStorage {
 	fanout: Pipe<SunsetRawMutex, READ_SIZE>,
     fanin: Pipe<SunsetRawMutex, WRITE_SIZE>,
     wake: Signal<SunsetRawMutex, ()>,
-    counter: u64,
 }
 
 impl TakePipeStorage {
@@ -61,7 +60,6 @@ impl Default for TakePipeStorage {
             fanout: Pipe::new(),
             fanin: Pipe::new(),
             wake: Signal::new(),
-            counter: 0,
         }
     }
 }
@@ -216,7 +214,7 @@ impl asynch::Write for TakeWrite<'_> {
             // write completed
             Either::First(l) => l,
             // lost the pipe
-            Either::Second(l) => {
+            Either::Second(_) => {
                 self.shared = None;
                 Err(sunset::Error::ChannelEOF)
             }
diff --git a/embassy/demos/picow/src/usbserial.rs b/embassy/demos/picow/src/usbserial.rs
index 04fc999..f4fa29a 100644
--- a/embassy/demos/picow/src/usbserial.rs
+++ b/embassy/demos/picow/src/usbserial.rs
@@ -7,7 +7,7 @@ pub use log::{debug, error, info, log, trace, warn};
 pub use defmt::{debug, error, info, panic, trace, warn};
 
 use embassy_futures::join::{join, join3};
-use embassy_rp::usb::{Instance, InterruptHandler};
+use embassy_rp::usb::{InterruptHandler};
 use embassy_rp::bind_interrupts;
 use embassy_rp::peripherals::USB;
 use embassy_usb::class::cdc_acm::{self, CdcAcmClass, State};
@@ -16,9 +16,6 @@ use embassy_usb_driver::Driver;
 
 use embedded_io::{asynch, Io, asynch::BufRead};
 
-use heapless::Vec;
-
-use sunset::*;
 use sunset_embassy::*;
 
 use crate::*;
diff --git a/embassy/demos/picow/src/wifi.rs b/embassy/demos/picow/src/wifi.rs
index 98a8ad4..c933d69 100644
--- a/embassy/demos/picow/src/wifi.rs
+++ b/embassy/demos/picow/src/wifi.rs
@@ -66,9 +66,8 @@ pub(crate) async fn wifi_stack(spawner: &Spawner,
 
     // TODO: this should move out of the critical path, run in the bg.
     // just return control before joining.
-    let mut status = Ok(());
-    for i in 0..2 {
-        status = if let Some(ref pw) = wpa_password {
+    for _ in 0..2 {
+        let status = if let Some(ref pw) = wpa_password {
             info!("wifi net {} wpa2", wifi_net);
             control.join_wpa2(&wifi_net, &pw).await
         } else {
diff --git a/embassy/src/embassy_sunset.rs b/embassy/src/embassy_sunset.rs
index 62eea99..0dc7a71 100644
--- a/embassy/src/embassy_sunset.rs
+++ b/embassy/src/embassy_sunset.rs
@@ -18,7 +18,7 @@ use embassy_sync::mutex::Mutex;
 use embassy_sync::signal::Signal;
 use embassy_futures::select::select;
 use embassy_futures::join;
-use embedded_io::{asynch, asynch::Write, Io};
+use embedded_io::{asynch, Io};
 
 // thumbv6m has no atomic usize add/sub
 use atomic_polyfill::AtomicUsize;
@@ -140,7 +140,7 @@ impl<'a, C: CliBehaviour, S: ServBehaviour> EmbassySunset<'a, C, S> {
                 let mut buf = [0; 1024];
                 let l = self.output(&mut buf).await?;
                 wsock.write_all(&buf[..l]).await
-                .map_err(|e| {
+                .map_err(|_| {
                     info!("socket write error");
                     Error::ChannelEOF
                 })?;
@@ -155,7 +155,7 @@ impl<'a, C: CliBehaviour, S: ServBehaviour> EmbassySunset<'a, C, S> {
                 // TODO: make sunset read directly from socket, no intermediate buffer.
                 let mut buf = [0; 1024];
                 let l = rsock.read(&mut buf).await
-                .map_err(|e| {
+                .map_err(|_| {
                     info!("socket read error");
                     Error::ChannelEOF
                 })?;
@@ -545,7 +545,7 @@ pub async fn io_copy_nowriteerror<const B: usize, R, W>(r: &mut R, w: &mut W) ->
             return sunset::error::ChannelEOF.fail();
         }
         let b = &b[..n];
-        if let Err(e) = w.write_all(b).await {
+        if let Err(_) = w.write_all(b).await {
             info!("write error");
         }
     }
@@ -577,7 +577,7 @@ pub async fn io_buf_copy_noreaderror<R, W>(r: &mut R, w: &mut W) -> Result<()>
     loop {
         let b = match r.fill_buf().await {
             Ok(b) => b,
-            Err(e) => {
+            Err(_) => {
                 info!("read error");
                 embassy_futures::yield_now().await;
                 continue;
diff --git a/src/behaviour.rs b/src/behaviour.rs
index c9a48ff..7d1c5db 100644
--- a/src/behaviour.rs
+++ b/src/behaviour.rs
@@ -301,7 +301,7 @@ impl CliBehaviour for UnusedCli {
     fn username(&mut self) -> BhResult<ResponseString> {
         unreachable!()
     }
-    fn valid_hostkey(&mut self, key: &PubKey) -> BhResult<bool> {
+    fn valid_hostkey(&mut self, _key: &PubKey) -> BhResult<bool> {
         unreachable!()
     }
     fn authenticated(&mut self) {
@@ -317,7 +317,7 @@ impl ServBehaviour for UnusedServ {
     fn hostkeys(&mut self) -> BhResult<heapless::Vec<&SignKey, 2>> {
         unreachable!()
     }
-    fn open_session(&mut self, chan: ChanHandle) -> channel::ChanOpened {
+    fn open_session(&mut self, _chan: ChanHandle) -> channel::ChanOpened {
         unreachable!()
     }
 }
diff --git a/src/channel.rs b/src/channel.rs
index 352044d..03a2ab1 100644
--- a/src/channel.rs
+++ b/src/channel.rs
@@ -329,7 +329,7 @@ impl<C: CliBehaviour, S: ServBehaviour> Channels<C, S> {
                             // let the CliBehaviour open a shell etc
                             let mut opener = SessionOpener::new(&ch, s);
                             let r = b.client()?.session_opened(ch.num(), &mut opener).await;
-                            if let Err(e) = r {
+                            if let Err(_) = r {
                                 trace!("Error from session_opened");
                             }
                         }
diff --git a/src/cliauth.rs b/src/cliauth.rs
index 80af9e3..537f5c9 100644
--- a/src/cliauth.rs
+++ b/src/cliauth.rs
@@ -144,7 +144,7 @@ impl CliAuth {
         b: &mut impl CliBehaviour,
     ) -> Option<Req> {
         loop {
-            let k = b.next_authkey().unwrap_or_else(|e| {
+            let k = b.next_authkey().unwrap_or_else(|_| {
                 warn!("Error getting pubkey for auth");
                 None
             });
@@ -220,7 +220,7 @@ impl CliAuth {
 
         match auth60 {
             Userauth60::PkOk(pkok) => self.auth_pkok(pkok, sess_id, parse_ctx, s, b).await,
-            Userauth60::PwChangeReq(_req) => todo!("pwchange"),
+            Userauth60::PwChangeReq(_req) => self.change_password(),
         }
     }
 
@@ -255,6 +255,11 @@ impl CliAuth {
         Err(Error::SSHProtoError)
     }
 
+    fn change_password(&self) -> Result<()> {
+        // Doesn't seem to be widely implemented, we'll just fail.
+        Err(Error::msg("Password has expired"))
+    }
+
     pub async fn failure(
         &mut self,
         failure: &packets::UserauthFailure<'_>,
diff --git a/src/client.rs b/src/client.rs
index d9f02f8..05ada6f 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -27,14 +27,10 @@ impl Client {
     pub(crate) fn auth_success(
         &mut self,
         parse_ctx: &mut ParseContext,
-        s: &mut TrafSend,
         b: &mut impl CliBehaviour,
     ) -> Result<()> {
         parse_ctx.cli_auth_type = None;
 
-        // github.com doesn't like this, openssh doesn't send it
-        // s.send(packets::ServiceRequest { name: SSH_SERVICE_CONNECTION })?;
-
         self.auth.success(b)
     }
 
diff --git a/src/conn.rs b/src/conn.rs
index d8f236c..1df9743 100644
--- a/src/conn.rs
+++ b/src/conn.rs
@@ -260,7 +260,7 @@ impl<C: CliBehaviour, S: ServBehaviour> Conn<C, S> {
                     return Err(Error::SSHProtoError);
                 }
 
-                self.kex.handle_kexdhreply(&p, s, b.client()?).await?;
+                self.kex.handle_kexdhreply(&p, s, b.client()?, self.sess_id.is_none()).await?;
             }
             Packet::NewKeys(_) => {
                 self.kex.handle_newkeys(&mut self.sess_id, s)?;
@@ -327,7 +327,7 @@ impl<C: CliBehaviour, S: ServBehaviour> Conn<C, S> {
                 if let ClientServer::Client(cli) = &mut self.cliserv {
                     if matches!(self.state, ConnState::PreAuth) {
                         self.state = ConnState::Authed;
-                        cli.auth_success(&mut self.parse_ctx, s, b.client()?)?;
+                        cli.auth_success(&mut self.parse_ctx, b.client()?)?;
                     } else {
                         debug!("Received UserauthSuccess unrequested")
                     }
@@ -375,7 +375,7 @@ impl<C: CliBehaviour, S: ServBehaviour> Conn<C, S> {
                     s.send(packets::RequestFailure {})?;
                 }
             }
-            Packet::RequestSuccess(p) => {
+            Packet::RequestSuccess(_p) => {
                 trace!("Got global request success")
             }
             Packet::RequestFailure(_) => {
diff --git a/src/kex.rs b/src/kex.rs
index 2becba9..b7e3cfb 100644
--- a/src/kex.rs
+++ b/src/kex.rs
@@ -338,6 +338,7 @@ impl Kex {
         &mut self, p: &packets::KexDHReply<'f>,
         s: &mut TrafSend<'_, '_>,
         b: &mut impl CliBehaviour,
+        first_kex: bool,
     ) -> Result<()> {
         if let Kex::KexDH { algos, ..} = self {
             if !algos.is_client {
@@ -353,14 +354,31 @@ impl Kex {
 
         if let Kex::KexDH { mut algos, kex_hash } = self.take() {
             let output = SharedSecret::handle_kexdhreply(&mut algos, kex_hash, p, b).await?;
-            *self = Kex::NewKeys { output, algos };
             s.send(packets::NewKeys {})?;
+
+            if first_kex && algos.send_ext_info {
+                self.send_ext_info(s)?;
+            }
+
+            *self = Kex::NewKeys { output, algos };
             Ok(())
         } else {
             error::PacketWrong.fail()
         }
     }
 
+    pub fn send_ext_info(&self, s: &mut TrafSend) -> Result<()> {
+        if cfg!(feature = "rsa") {
+            // OK unwrap: namelist has capacity
+            let algs = ([SSH_NAME_RSA_SHA256, SSH_NAME_ED25519].as_slice()).try_into().unwrap();
+            let ext = packets::ExtInfo {
+                server_sig_algs: Some(NameList::Local(&algs)),
+            };
+            s.send(ext)?;
+        }
+        Ok(())
+    }
+
     pub fn handle_newkeys(&mut self, sess_id: &mut Option<SessId>, s: &mut TrafSend<'_, '_>) -> Result<()> {
         if let Kex::NewKeys { output, algos } = self.take() {
             // We will have already sent our own NewKeys message if we reach thi
@@ -377,6 +395,7 @@ impl Kex {
         }
     }
 
+
     /// Perform SSH algorithm negotiation
     fn algo_negotiation(
         is_client: bool, p: &packets::KexInit, conf: &AlgoConfig,
@@ -405,10 +424,11 @@ impl Kex {
 
         // we only send MSG_EXT_INFO to a client, don't look
         // for SSH_NAME_EXT_INFO_S
-        let send_ext_info = match is_client {
-            true => false,
+        let send_ext_info = if is_client {
+            false
+        } else {
             // OK unwrap: p.kex is a remote list
-            false => p.kex.has_algo(SSH_NAME_EXT_INFO_C).unwrap(),
+            p.kex.has_algo(SSH_NAME_EXT_INFO_C).unwrap()
         };
 
         debug!("hostsig {:?}    vs   {:?}", p.hostsig, conf.hostsig);
@@ -693,7 +713,7 @@ impl KexCurve25519 {
         let mut s = [0u8; 32];
         random::fill_random(s.as_mut_slice())?;
         // TODO: check that pure random bytes are OK
-        let ours = x25519_dalek::EphemeralSecret::new(OsRng);
+        let ours = x25519_dalek::EphemeralSecret::random_from_rng(OsRng);
         let pubkey = x25519_dalek::PublicKey::from(&ours);
         let pubkey = pubkey.to_bytes();
         Ok(KexCurve25519 { ours: Some(ours), pubkey })
diff --git a/src/packets.rs b/src/packets.rs
index 7b1efd9..a7ed113 100644
--- a/src/packets.rs
+++ b/src/packets.rs
@@ -841,7 +841,7 @@ impl TryFrom<u8> for MessageNumber {
     fn try_from(v: u8) -> Result<Self> {
         match v {
             // eg
-            // 20 = Ok(MessageNumber::SSH_MSG_KEXINIT)
+            // 20 => Ok(MessageNumber::SSH_MSG_KEXINIT)
             $(
             $message_num => Ok(MessageNumber::$SSH_MESSAGE_NAME),
             )*
diff --git a/src/sign.rs b/src/sign.rs
index d2299ac..419812c 100644
--- a/src/sign.rs
+++ b/src/sign.rs
@@ -372,7 +372,7 @@ impl TryFrom<ssh_key::PrivateKey> for SignKey {
     fn try_from(k: ssh_key::PrivateKey) -> Result<Self> {
         match k.key_data() {
             ssh_key::private::KeypairData::Ed25519(k) => {
-                Ok(SignKey::Ed25519(k.private.to_bytes()))
+                Ok(SignKey::Ed25519(k.private.to_bytes().into()))
             }
 
             #[cfg(feature = "rsa")]
diff --git a/src/sshnames.rs b/src/sshnames.rs
index 57ec5bf..d631a91 100644
--- a/src/sshnames.rs
+++ b/src/sshnames.rs
@@ -87,4 +87,5 @@ pub enum AgentMessageNum {
 
 }
 
+/// [draft-miller-ssh-agent-04](https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04)
 pub const SSH_AGENT_FLAG_RSA_SHA2_256: u32 = 0x02;
-- 
GitLab